2
0
mirror of https://github.com/xcat2/xNBA.git synced 2026-09-30 14:55:11 +00:00

Merge branch 'master' of git://git.ipxe.org/ipxe

This commit is contained in:
Jarrod Johnson
2011-01-07 15:57:40 -05:00
107 changed files with 9011 additions and 1403 deletions
+1
View File
@@ -65,6 +65,7 @@ SRCDIRS += drivers/net
SRCDIRS += drivers/net/e1000
SRCDIRS += drivers/net/e1000e
SRCDIRS += drivers/net/igb
SRCDIRS += drivers/net/igbvf
SRCDIRS += drivers/net/phantom
SRCDIRS += drivers/net/rtl818x
SRCDIRS += drivers/net/ath5k
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
+31 -17
View File
@@ -43,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** An UNDI NIC */
struct undi_nic {
/** Device supports IRQs */
int irq_supported;
/** Assigned IRQ number */
unsigned int irq;
/** Currently processing ISR */
@@ -251,8 +253,10 @@ static void undinet_poll ( struct net_device *netdev ) {
int rc;
if ( ! undinic->isr_processing ) {
/* Do nothing unless ISR has been triggered */
if ( ! undinet_isr_triggered() ) {
/* If interrupts are supported, then do nothing unless
* the ISR has been triggered.
*/
if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){
/* Allow interrupt to occur */
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
"nop\n\t"
@@ -357,10 +361,12 @@ static int undinet_open ( struct net_device *netdev ) {
struct s_PXENV_UNDI_OPEN undi_open;
int rc;
/* Hook interrupt service routine and enable interrupt */
undinet_hook_isr ( undinic->irq );
enable_irq ( undinic->irq );
send_eoi ( undinic->irq );
/* Hook interrupt service routine and enable interrupt if supported */
if ( undinic->irq_supported ) {
undinet_hook_isr ( undinic->irq );
enable_irq ( undinic->irq );
send_eoi ( undinic->irq );
}
/* Set station address. Required for some PXE stacks; will
* spuriously fail on others. Ignore failures. We only ever
@@ -425,9 +431,11 @@ static void undinet_close ( struct net_device *netdev ) {
pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
&undi_close, sizeof ( undi_close ) );
/* Disable interrupt and unhook ISR */
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
/* Disable interrupt and unhook ISR if supported */
if ( undinic->irq_supported ) {
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
}
DBGC ( undinic, "UNDINIC %p closed\n", undinic );
}
@@ -524,13 +532,8 @@ int undinet_probe ( struct undi_device *undi ) {
goto err_undi_get_information;
memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
undinic->irq = undi_info.IntNumber;
if ( undinic->irq > IRQ_MAX ) {
DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n",
undinic, undinic->irq );
goto err_bad_irq;
}
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
DBGC ( undinic, "UNDINIC %p has MAC address %s\n",
undinic, eth_ntoa ( netdev->hw_addr ) );
/* Get interface information */
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
@@ -541,6 +544,17 @@ int undinet_probe ( struct undi_device *undi ) {
DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
undi_iface.ServiceFlags );
if ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) {
if ( undinic->irq > IRQ_MAX ) {
DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
undinic, undinic->irq );
rc = -EINVAL;
goto err_bad_irq;
}
undinic->irq_supported = 1;
DBGC ( undinic, "UNDINIC %p uses IRQ %d\n",
undinic, undinic->irq );
}
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
@@ -559,8 +573,8 @@ int undinet_probe ( struct undi_device *undi ) {
return 0;
err_register:
err_undi_get_iface_info:
err_bad_irq:
err_undi_get_iface_info:
err_undi_get_information:
err_undi_initialize:
/* Shut down UNDI stack */
+73 -2
View File
@@ -1,26 +1,97 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <ipxe/netdevice.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <hci/ifmgmt_cmd.h>
#include <pxe_call.h>
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* PXE commands
*
*/
/** "startpxe" command descriptor */
static struct command_descriptor startpxe_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>]", "" );
/**
* "startpxe" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int startpxe_payload ( struct net_device *netdev ) {
if ( netdev_is_open ( netdev ) )
pxe_activate ( netdev );
return 0;
}
/**
* The "startpxe" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int startpxe_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv, startpxe_payload,
"Activate PXE on" );
return ifcommon_exec ( argc, argv, &startpxe_cmd, startpxe_payload, 0 );
}
/** "stoppxe" options */
struct stoppxe_options {};
/** "stoppxe" option list */
static struct option_descriptor stoppxe_opts[] = {};
/** "stoppxe" command descriptor */
static struct command_descriptor stoppxe_cmd =
COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0,
"", "" );
/**
* The "stoppxe" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int stoppxe_exec ( int argc __unused, char **argv __unused ) {
struct stoppxe_options opts;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &stoppxe_cmd, &opts ) ) != 0 )
return rc;
pxe_deactivate();
return 0;
}
/** PXE commands */
struct command pxe_commands[] __command = {
{
.name = "startpxe",
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <realmode.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Reboot command
*
*/
/** "reboot" options */
struct reboot_options {};
/** "reboot" option list */
static struct option_descriptor reboot_opts[] = {};
/** "reboot" command descriptor */
static struct command_descriptor reboot_cmd =
COMMAND_DESC ( struct reboot_options, reboot_opts, 0, 0, "", "" );
/**
* The "reboot" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int reboot_exec ( int argc, char **argv ) {
struct reboot_options opts;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &reboot_cmd, &opts ) ) != 0 )
return rc;
/* Reboot system */
__asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : : );
return 0;
}
/** "reboot" command */
struct command reboot_command __command = {
.name = "reboot",
.exec = reboot_exec,
};
+14 -9
View File
@@ -166,11 +166,13 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
/* Record source IP address */
pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
DBG ( " %s", inet_ntoa ( pxe_udp.local.sin_addr ) );
DBG ( " %s\n", inet_ntoa ( pxe_udp.local.sin_addr ) );
/* Open promiscuous UDP connection */
intf_restart ( &pxe_udp.xfer, 0 );
if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) {
DBG ( "PXENV_UDP_OPEN could not open promiscuous socket: %s\n",
strerror ( rc ) );
pxenv_udp_open->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
}
@@ -201,7 +203,7 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
*
*/
PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
DBG ( "PXENV_UDP_CLOSE" );
DBG ( "PXENV_UDP_CLOSE\n" );
/* Close UDP connection */
intf_restart ( &pxe_udp.xfer, 0 );
@@ -288,6 +290,7 @@ PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
len = pxenv_udp_write->buffer_size;
iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
if ( ! iobuf ) {
DBG ( " out of memory\n" );
pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
return PXENV_EXIT_FAILURE;
}
@@ -295,7 +298,7 @@ PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
pxenv_udp_write->buffer.offset );
copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
ntohs ( pxenv_udp_write->src_port ),
inet_ntoa ( dest.sin_addr ),
@@ -303,6 +306,8 @@ PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
/* Transmit packet */
if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
strerror ( rc ) );
pxenv_udp_write->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
}
@@ -360,36 +365,36 @@ PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
uint16_t d_port_wanted = pxenv_udp_read->d_port;
uint16_t d_port;
DBG ( "PXENV_UDP_READ" );
/* Try receiving a packet */
pxe_udp.pxenv_udp_read = pxenv_udp_read;
step();
if ( pxe_udp.pxenv_udp_read ) {
/* No packet received */
DBG2 ( "PXENV_UDP_READ\n" );
pxe_udp.pxenv_udp_read = NULL;
goto no_packet;
}
dest_ip.s_addr = pxenv_udp_read->dest_ip;
d_port = pxenv_udp_read->d_port;
DBG ( "PXENV_UDP_READ" );
/* Filter on destination address and/or port */
if ( dest_ip_wanted.s_addr &&
( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
DBG ( " (wanted %s)", inet_ntoa ( dest_ip_wanted ) );
DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
goto no_packet;
}
if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
DBG ( " wrong port %d ", htons ( d_port ) );
DBG ( " (wanted %d)", htons ( d_port_wanted ) );
DBG ( " wrong port %d", htons ( d_port ) );
DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
goto no_packet;
}
DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
DBG ( "%d<-%s:%d", ntohs ( pxenv_udp_read->s_port ),
DBG ( "%d<-%s:%d\n", ntohs ( pxenv_udp_read->s_port ),
inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
ntohs ( pxenv_udp_read->d_port ) );
+27 -16
View File
@@ -58,8 +58,10 @@ struct net_device *pxe_netdev = NULL;
* @v netdev Network device, or NULL
*/
void pxe_set_netdev ( struct net_device *netdev ) {
if ( pxe_netdev )
if ( pxe_netdev ) {
netdev_rx_unfreeze ( pxe_netdev );
netdev_put ( pxe_netdev );
}
pxe_netdev = NULL;
if ( netdev )
pxe_netdev = netdev_get ( netdev );
@@ -76,6 +78,7 @@ static int pxe_netdev_open ( void ) {
if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
return rc;
netdev_rx_freeze ( pxe_netdev );
netdev_irq ( pxe_netdev, 1 );
return 0;
}
@@ -85,6 +88,7 @@ static int pxe_netdev_open ( void ) {
*
*/
static void pxe_netdev_close ( void ) {
netdev_rx_unfreeze ( pxe_netdev );
netdev_irq ( pxe_netdev, 0 );
netdev_close ( pxe_netdev );
undi_tx_count = 0;
@@ -228,17 +232,17 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
char destaddr[MAX_LL_ADDR_LEN];
const void *ll_dest;
size_t ll_hlen = ll_protocol->ll_header_len;
size_t len;
unsigned int i;
int rc;
DBG2 ( "PXENV_UNDI_TRANSMIT" );
/* Forcibly enable interrupts at this point, to work around
* callers that never call PXENV_UNDI_OPEN before attempting
* to use the UNDI API.
/* Forcibly enable interrupts and freeze receive queue
* processing at this point, to work around callers that never
* call PXENV_UNDI_OPEN before attempting to use the UNDI API.
*/
netdev_rx_freeze ( pxe_netdev );
netdev_irq ( pxe_netdev, 1 );
/* Identify network-layer protocol */
@@ -248,7 +252,6 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
case P_RARP: net_protocol = &rarp_protocol; break;
case P_UNKNOWN:
net_protocol = NULL;
ll_hlen = 0;
break;
default:
DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
@@ -271,13 +274,13 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
}
/* Allocate and fill I/O buffer */
iobuf = alloc_iob ( ll_hlen + len );
iobuf = alloc_iob ( MAX_LL_HEADER_LEN + len );
if ( ! iobuf ) {
DBG2 ( " could not allocate iobuf\n" );
undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
return PXENV_EXIT_FAILURE;
}
iob_reserve ( iobuf, ll_hlen );
iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
tbd.Xmit.offset, tbd.ImmedLength );
for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
@@ -558,12 +561,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
info->BusDevFunc = dev->desc.location;
/* Cheat: remaining fields are probably unnecessary,
* and would require adding extra code to pci.c.
/* Earlier versions of the PXE specification do not
* have the SubVendor_ID and SubDevice_ID fields. It
* is possible that some NBPs will not provide space
* for them, and so we must not fill them in.
*/
undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
DBG ( " PCI %02x:%02x.%x %04x:%04x (%04x:%04x) %02x%02x%02x "
DBG ( " PCI %02x:%02x.%x %04x:%04x ('%04x:%04x') %02x%02x%02x "
"rev %02x\n", PCI_BUS ( info->BusDevFunc ),
PCI_SLOT ( info->BusDevFunc ),
PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
@@ -672,7 +675,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
/* Call poll(). This should acknowledge the device
* interrupt and queue up any received packet.
*/
netdev_poll ( pxe_netdev );
net_poll();
/* A 100% accurate determination of "OURS" vs "NOT
* OURS" is difficult to achieve without invasive and
@@ -711,7 +714,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
* PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
* cope with these out-of-spec clients.
*/
netdev_poll ( pxe_netdev );
net_poll();
/* If we have not yet marked a TX as complete, and the
* netdev TX queue is empty, report the TX completion.
@@ -782,7 +785,15 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
undi_isr->Frame.segment = rm_ds;
undi_isr->Frame.offset = __from_data16 ( basemem_packet );
undi_isr->ProtType = prottype;
undi_isr->PktType = XMT_DESTADDR;
if ( memcmp ( ll_dest, pxe_netdev->ll_addr,
ll_protocol->ll_addr_len ) == 0 ) {
undi_isr->PktType = P_DIRECTED;
} else if ( memcmp ( ll_dest, pxe_netdev->ll_broadcast,
ll_protocol->ll_addr_len ) == 0 ) {
undi_isr->PktType = P_BROADCAST;
} else {
undi_isr->PktType = P_MULTICAST;
}
DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
undi_isr->Frame.segment, undi_isr->Frame.offset,
undi_isr->BufferLength, undi_isr->FrameLength,
+18 -12
View File
@@ -165,14 +165,23 @@ test_a20_long:
pushl %ecx
movl $TEST_A20_LONG_MAX_RETRIES, %ecx
1: pushw %ax
pushw %ds
pushw %es
/* Flatten real mode so we can access the test pattern's 1MB offset */
call flatten_real_mode
/* Set up segment registers for access across the 1MB boundary */
xorw %ax, %ax
movw %ax, %ds
decw %ax
movw %ax, %es
2: /* Modify and check test pattern; succeed if we see a difference */
incw %cs:test_a20_data
addr32 movw %cs:(test_a20_data + 0x100000 ), %ax
cmpw %cs:test_a20_data, %ax
pushfw
cli
xchgw %ds:0, %cx
movw %es:0x10, %ax
xchgw %ds:0, %cx
popfw
cmpw %ax, %cx
clc
jnz 99f
@@ -182,17 +191,13 @@ test_a20_long:
stc
99: /* Restore registers and return */
popw %es
popw %ds
popw %ax
popl %ecx
ret
.size test_a20_long, . - test_a20_long
.section ".text16.early.data", "aw", @progbits
.align 2
test_a20_data:
.word 0xdead
.size test_a20_data, . - test_a20_data
/****************************************************************************
* enable_a20_bios
*
@@ -414,6 +419,7 @@ enable_a20_method:
access_highmem:
/* Enable A20 line */
call enable_a20
/* CPU will be in flat real mode as a result of this call */
/* Set up 4GB limits */
call flatten_real_mode
lret
.size access_highmem, . - access_highmem
+6
View File
@@ -234,6 +234,12 @@ REQUIRE_OBJECT ( pxe_cmd );
#ifdef LOTEST_CMD
REQUIRE_OBJECT ( lotest_cmd );
#endif
#ifdef VLAN_CMD
REQUIRE_OBJECT ( vlan_cmd );
#endif
#ifdef REBOOT_CMD
REQUIRE_OBJECT ( reboot_cmd );
#endif
/*
* Drag in miscellaneous objects
-1
View File
@@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define PXE_STACK /* PXE stack in iPXE - required for PXELINUX */
#define PXE_MENU /* PXE menu booting */
#define PXE_CMD /* PXE commands */
#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */
#define SANBOOT_PROTO_AOE /* AoE protocol */
+3 -1
View File
@@ -123,7 +123,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#undef TIME_CMD /* Time commands */
#undef DIGEST_CMD /* Image crypto digest commands */
#undef LOTEST_CMD /* Loopback testing commands */
//#undef PXE_CMD /* PXE commands */
#undef VLAN_CMD /* VLAN commands */
#undef PXE_CMD /* PXE commands */
#undef REBOOT_CMD /* Reboot command */
/*
* Error message tables to include
+20
View File
@@ -1,3 +1,23 @@
/*
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/md5.h>
/**
* Print an MD5 checksum with specified display address
*
* @v dispaddr Display address
* @v data Data to checksum
* @v len Length of data
*/
void dbg_md5_da ( unsigned long dispaddr, const void *data,
unsigned long len ) {
struct digest_algorithm *digest = &md5_algorithm;
uint8_t digest_ctx[digest->ctxsize];
uint8_t digest_out[digest->digestsize];
unsigned int i;
printf ( "md5sum ( %#08lx, %#lx ) = ", dispaddr, len );
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, data, len );
digest_final ( digest, digest_ctx, digest_out );
for ( i = 0 ; i < sizeof ( digest_out ) ; i++ )
printf ( "%02x", digest_out[i] );
printf ( "\n" );
}
+247 -52
View File
@@ -29,7 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <assert.h>
#include <ipxe/tables.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/settings.h>
#include <ipxe/shell.h>
/** @file
*
@@ -37,16 +39,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/* Avoid dragging in getopt.o unless a command really uses it */
int optind;
int nextchar;
/** Shell stop state */
static int stop_state;
/**
* Execute command
*
* @v command Command name
* @v argv Argument list
* @ret rc Command exit status
* @ret rc Return status code
*
* Execute the named command. Unlike a traditional POSIX execv(),
* this function returns the exit status of the command.
@@ -58,12 +59,12 @@ int execv ( const char *command, char * const argv[] ) {
/* Count number of arguments */
for ( argc = 0 ; argv[argc] ; argc++ ) {}
/* An empty command is deemed to do nothing, successfully */
if ( command == NULL )
return 0;
/* Sanity checks */
if ( ! command ) {
DBG ( "No command\n" );
return -EINVAL;
}
if ( ! argc ) {
if ( argc == 0 ) {
DBG ( "%s: empty argument list\n", command );
return -EINVAL;
}
@@ -115,17 +116,21 @@ static char * expand_command ( const char *command ) {
head = expcmd;
/* Locate opener */
start = strstr ( expcmd, "${" );
if ( ! start )
/* Locate setting to be expanded */
start = NULL;
end = NULL;
for ( tmp = expcmd ; *tmp ; tmp++ ) {
if ( ( tmp[0] == '$' ) && ( tmp[1] == '{' ) )
start = tmp;
if ( start && ( tmp[0] == '}' ) ) {
end = tmp;
break;
}
}
if ( ! end )
break;
*start = '\0';
name = ( start + 2 );
/* Locate closer */
end = strstr ( name, "}" );
if ( ! end )
break;
*end = '\0';
tail = ( end + 1 );
@@ -156,83 +161,192 @@ static char * expand_command ( const char *command ) {
}
/**
* Split command line into argv array
* Split command line into tokens
*
* @v args Command line
* @v argv Argument array to populate, or NULL
* @ret argc Argument count
* @v command Command line
* @v tokens Token list to populate, or NULL
* @ret count Number of tokens
*
* Splits the command line into whitespace-delimited arguments. If @c
* argv is non-NULL, any whitespace in the command line will be
* Splits the command line into whitespace-delimited tokens. If @c
* tokens is non-NULL, any whitespace in the command line will be
* replaced with NULs.
*/
static int split_args ( char *args, char * argv[] ) {
int argc = 0;
static int split_command ( char *command, char **tokens ) {
int count = 0;
while ( 1 ) {
/* Skip over any whitespace / convert to NUL */
while ( isspace ( *args ) ) {
if ( argv )
*args = '\0';
args++;
while ( isspace ( *command ) ) {
if ( tokens )
*command = '\0';
command++;
}
/* Check for end of line */
if ( ! *args )
if ( ! *command )
break;
/* We have found the start of the next argument */
if ( argv )
argv[argc] = args;
argc++;
if ( tokens )
tokens[count] = command;
count++;
/* Skip to start of next whitespace, if any */
while ( *args && ! isspace ( *args ) ) {
args++;
while ( *command && ! isspace ( *command ) ) {
command++;
}
}
return argc;
return count;
}
/**
* Process next command only if previous command succeeded
*
* @v rc Status of previous command
* @ret process Process next command
*/
static int process_on_success ( int rc ) {
return ( rc == 0 );
}
/**
* Process next command only if previous command failed
*
* @v rc Status of previous command
* @ret process Process next command
*/
static int process_on_failure ( int rc ) {
return ( rc != 0 );
}
/**
* Find command terminator
*
* @v tokens Token list
* @ret process_next "Should next command be processed?" function
* @ret argc Argument count
*/
static int command_terminator ( char **tokens,
int ( **process_next ) ( int rc ) ) {
unsigned int i;
/* Find first terminating token */
for ( i = 0 ; tokens[i] ; i++ ) {
if ( tokens[i][0] == '#' ) {
/* Start of a comment */
break;
} else if ( strcmp ( tokens[i], "||" ) == 0 ) {
/* Short-circuit logical OR */
*process_next = process_on_failure;
return i;
} else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
/* Short-circuit logical AND */
*process_next = process_on_success;
return i;
}
}
/* End of token list */
*process_next = NULL;
return i;
}
/**
* Set shell stop state
*
* @v stop Shell stop state
*/
void shell_stop ( int stop ) {
stop_state = stop;
}
/**
* Test and consume shell stop state
*
* @v stop Shell stop state to consume
* @v stopped Shell had been stopped
*/
int shell_stopped ( int stop ) {
int stopped;
/* Test to see if we need to stop */
stopped = ( stop_state >= stop );
/* Consume stop state */
if ( stop_state <= stop )
stop_state = 0;
return stopped;
}
/**
* Execute command line
*
* @v command Command line
* @ret rc Command exit status
* @ret rc Return status code
*
* Execute the named command and arguments.
*/
int system ( const char *command ) {
char *args;
int ( * process_next ) ( int rc );
char *expcmd;
char **argv;
int argc;
int count;
int process;
int rc = 0;
/* Perform variable expansion */
args = expand_command ( command );
if ( ! args )
expcmd = expand_command ( command );
if ( ! expcmd )
return -ENOMEM;
/* Count arguments */
argc = split_args ( args, NULL );
/* Count tokens */
count = split_command ( expcmd, NULL );
/* Create argv array and execute command */
if ( argc ) {
char * argv[argc + 1];
/* Create token array */
if ( count ) {
char * tokens[count + 1];
split_args ( args, argv );
argv[argc] = NULL;
split_command ( expcmd, tokens );
tokens[count] = NULL;
process = 1;
if ( argv[0][0] != '#' )
rc = execv ( argv[0], argv );
for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
/* Find command terminator */
argc = command_terminator ( argv, &process_next );
/* Execute command */
if ( process ) {
argv[argc] = NULL;
rc = execv ( argv[0], argv );
}
/* Stop processing, if applicable */
if ( shell_stopped ( SHELL_STOP_COMMAND ) )
break;
/* Stop processing if we have reached the end
* of the command.
*/
if ( ! process_next )
break;
/* Determine whether or not to process next command */
process = process_next ( rc );
}
}
free ( args );
/* Free expanded command */
free ( expcmd );
return rc;
}
/**
* The "echo" command
* "echo" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int echo_exec ( int argc, char **argv ) {
int i;
@@ -249,3 +363,84 @@ struct command echo_command __command = {
.name = "echo",
.exec = echo_exec,
};
/** "exit" options */
struct exit_options {};
/** "exit" option list */
static struct option_descriptor exit_opts[] = {};
/** "exit" command descriptor */
static struct command_descriptor exit_cmd =
COMMAND_DESC ( struct exit_options, exit_opts, 0, 1,
"[<status>]", "" );
/**
* "exit" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int exit_exec ( int argc, char **argv ) {
struct exit_options opts;
unsigned int exit_code = 0;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &exit_cmd, &opts ) ) != 0 )
return rc;
/* Parse exit status, if present */
if ( optind != argc ) {
if ( ( rc = parse_integer ( argv[optind], &exit_code ) ) != 0 )
return rc;
}
/* Stop shell processing */
shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
return exit_code;
}
/** "exit" command */
struct command exit_command __command = {
.name = "exit",
.exec = exit_exec,
};
/** "isset" options */
struct isset_options {};
/** "isset" option list */
static struct option_descriptor isset_opts[] = {};
/** "isset" command descriptor */
static struct command_descriptor isset_cmd =
COMMAND_DESC ( struct isset_options, isset_opts, 0, MAX_ARGUMENTS,
"[...]", "" );
/**
* "isset" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int isset_exec ( int argc, char **argv ) {
struct isset_options opts;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &isset_cmd, &opts ) ) != 0 )
return rc;
/* Return success iff any arguments exist */
return ( ( optind == argc ) ? -ENOENT : 0 );
}
/** "isset" command */
struct command isset_command __command = {
.name = "isset",
.exec = isset_exec,
};
+106 -38
View File
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <ipxe/init.h>
#include <ipxe/uaccess.h>
#include <ipxe/io.h>
/** @file
*
@@ -30,12 +31,30 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
enum {
/** Constant for identifying valid trace buffers */
fnrec_magic = 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e',
/** Constant for identifying valid trace buffers */
#define FNREC_MAGIC ( 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e' )
/** Trace buffer length */
fnrec_buffer_length = 4096 / sizeof ( unsigned long ),
/** Number of trace buffer entries */
#define FNREC_NUM_ENTRIES 4096
/** Trace buffer physical address
*
* Fixed at 17MB
*/
#define FNREC_PHYS_ADDRESS ( 17 * 1024 * 1024 )
/** A trace buffer entry */
struct fnrec_entry {
/** Called function address */
void *called_fn;
/** Call site */
void *call_site;
/** Entry count */
uint16_t entry_count;
/** Exit count */
uint16_t exit_count;
/** Checksum */
unsigned long checksum;
};
/** A trace buffer */
@@ -44,10 +63,11 @@ struct fnrec_buffer {
uint32_t magic;
/** Next trace buffer entry to fill */
uint32_t idx;
unsigned int idx;
/** Function address trace buffer */
unsigned long data[fnrec_buffer_length];
/** Trace buffer */
struct fnrec_entry data[FNREC_NUM_ENTRIES]
__attribute__ (( aligned ( 64 ) ));
};
/** The trace buffer */
@@ -59,7 +79,15 @@ static struct fnrec_buffer *fnrec_buffer;
* @ret is_valid Buffer is valid
*/
static int fnrec_is_valid ( void ) {
return fnrec_buffer && fnrec_buffer->magic == fnrec_magic;
return ( fnrec_buffer && ( fnrec_buffer->magic == FNREC_MAGIC ) );
}
/**
* Invalidate the trace buffer
*
*/
static void fnrec_invalidate ( void ) {
fnrec_buffer->magic = 0;
}
/**
@@ -67,43 +95,64 @@ static int fnrec_is_valid ( void ) {
*/
static void fnrec_reset ( void ) {
memset ( fnrec_buffer, 0, sizeof ( *fnrec_buffer ) );
fnrec_buffer->magic = fnrec_magic;
fnrec_buffer->magic = FNREC_MAGIC;
}
/**
* Write a value to the end of the buffer if it is not a repetition
* Append an entry to the trace buffer
*
* @v l Value to append
* @v called_fn Called function
* @v call_site Call site
* @ret entry Trace buffer entry
*/
static void fnrec_append_unique ( unsigned long l ) {
static unsigned long lastval;
uint32_t idx = fnrec_buffer->idx;
static struct fnrec_entry * fnrec_append ( void *called_fn, void *call_site ) {
struct fnrec_entry *entry;
/* Avoid recording the same value repeatedly */
if ( l == lastval )
return;
/* Re-use existing entry, if possible */
entry = &fnrec_buffer->data[ fnrec_buffer->idx ];
if ( ( entry->called_fn == called_fn ) &&
( entry->call_site == call_site ) &&
( entry->entry_count >= entry->exit_count ) ) {
return entry;
}
fnrec_buffer->data[idx] = l;
fnrec_buffer->idx = ( idx + 1 ) % fnrec_buffer_length;
lastval = l;
/* Otherwise, create a new entry */
fnrec_buffer->idx = ( ( fnrec_buffer->idx + 1 ) % FNREC_NUM_ENTRIES );
entry = &fnrec_buffer->data[ fnrec_buffer->idx ];
entry->called_fn = called_fn;
entry->call_site = call_site;
entry->entry_count = 0;
entry->exit_count = 0;
entry->checksum = ( ( ( unsigned long ) called_fn ) ^
( ( unsigned long ) call_site ) );
return entry;
}
/**
* Print the contents of the trace buffer in chronological order
*/
static void fnrec_dump ( void ) {
size_t i;
if ( !fnrec_is_valid() ) {
printf ( "fnrec buffer not found\n" );
return;
}
struct fnrec_entry *entry;
unsigned int i;
unsigned int idx;
unsigned long checksum;
printf ( "fnrec buffer dump:\n" );
for ( i = 0; i < fnrec_buffer_length; i++ ) {
unsigned long l = fnrec_buffer->data[
( fnrec_buffer->idx + i ) % fnrec_buffer_length];
printf ( "%08lx%c", l, i % 8 == 7 ? '\n' : ' ' );
for ( i = 1 ; i <= FNREC_NUM_ENTRIES ; i++ ) {
idx = ( ( fnrec_buffer->idx + i ) % FNREC_NUM_ENTRIES );
entry = &fnrec_buffer->data[idx];
if ( ( entry->entry_count == 0 ) && ( entry->exit_count == 0 ) )
continue;
checksum = ( ( ( ( unsigned long ) entry->called_fn ) ^
( ( unsigned long ) entry->call_site ) ) +
entry->entry_count + entry->exit_count );
printf ( "%p %p %d %d", entry->called_fn, entry->call_site,
entry->entry_count, entry->exit_count );
if ( entry->checksum != checksum ) {
printf ( " (checksum wrong at phys %08lx)",
virt_to_phys ( entry ) );
}
printf ( "\n");
}
}
@@ -111,9 +160,14 @@ static void fnrec_dump ( void ) {
* Function tracer initialisation function
*/
static void fnrec_init ( void ) {
/* Hardcoded to 17 MB */
fnrec_buffer = phys_to_virt ( 17 * 1024 * 1024 );
fnrec_dump();
fnrec_buffer = phys_to_virt ( FNREC_PHYS_ADDRESS );
if ( fnrec_is_valid() ) {
fnrec_invalidate();
fnrec_dump();
} else {
printf ( "fnrec buffer not found\n" );
}
fnrec_reset();
}
@@ -125,10 +179,24 @@ struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = {
* These functions are called from every C function. The compiler inserts
* these calls when -finstrument-functions is used.
*/
void __cyg_profile_func_enter ( void *called_fn, void *call_site __unused ) {
if ( fnrec_is_valid() )
fnrec_append_unique ( ( unsigned long ) called_fn );
void __cyg_profile_func_enter ( void *called_fn, void *call_site ) {
struct fnrec_entry *entry;
if ( fnrec_is_valid() ) {
entry = fnrec_append ( called_fn, call_site );
entry->entry_count++;
entry->checksum++;
mb();
}
}
void __cyg_profile_func_exit ( void *called_fn __unused, void *call_site __unused ) {
void __cyg_profile_func_exit ( void *called_fn, void *call_site ) {
struct fnrec_entry *entry;
if ( fnrec_is_valid() ) {
entry = fnrec_append ( called_fn, call_site );
entry->exit_count++;
entry->checksum++;
mb();
}
}
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <assert.h>
#include <ipxe/serial.h>
#include <ipxe/gdbstub.h>
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* @file
*
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <string.h>
#include <byteswap.h>
+22 -9
View File
@@ -197,15 +197,14 @@ static struct settings_operations nvo_settings_operations = {
*
* @v nvo Non-volatile options block
* @v nvs Underlying non-volatile storage device
* @v fragments List of option-containing fragments
* @v fragments List of option-containing fragments, or NULL
* @v refcnt Containing object reference counter, or NULL
*/
void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
struct nvo_fragment *fragments, struct refcnt *refcnt ) {
nvo->nvs = nvs;
nvo->fragments = fragments;
settings_init ( &nvo->settings, &nvo_settings_operations, refcnt,
"nvo", 0 );
settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 );
}
/**
@@ -219,24 +218,38 @@ int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
struct nvo_fragment *fragment = nvo->fragments;
int rc;
/* Calculate total length of all fragments */
for ( fragment = nvo->fragments ; fragment->len ; fragment++ )
nvo->total_len += fragment->len;
/* Calculate total length of all fragments, if applicable */
if ( fragment ) {
for ( ; fragment->len ; fragment++ )
nvo->total_len += fragment->len;
} else {
nvo->total_len = nvo->nvs->size;
}
/* Allocate memory for options and read in from NVS */
nvo->data = malloc ( nvo->total_len );
/* Allocate memory for options (and fragment list, if applicable) */
nvo->data = zalloc ( nvo->total_len +
( fragment ? 0 : ( 2 * sizeof ( *fragment ) ) ) );
if ( ! nvo->data ) {
DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
nvo, nvo->total_len );
rc = -ENOMEM;
goto err_malloc;
}
/* Create fragment list, if applicable */
if ( ! fragment ) {
fragment = ( nvo->data + nvo->total_len );
fragment->len = nvo->total_len;
nvo->fragments = fragment;
}
/* Read data from NVS */
if ( ( rc = nvo_load ( nvo ) ) != 0 )
goto err_load;
/* Verify and register options */
nvo_init_dhcpopts ( nvo );
if ( ( rc = register_settings ( &nvo->settings, parent ) ) != 0 )
if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
goto err_register;
DBGC ( nvo, "NVO %p registered\n", nvo );
+219
View File
@@ -0,0 +1,219 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/netdevice.h>
#include <ipxe/image.h>
#include <ipxe/parseopt.h>
/** @file
*
* Command line option parsing
*
*/
/** Return status code for "--help" option */
#define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
#define EINFO_ECANCELED_NO_OP \
__einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
/**
* Parse string value
*
* @v text Text
* @ret value String value
* @ret rc Return status code
*/
int parse_string ( const char *text, const char **value ) {
/* Sanity check */
assert ( text != NULL );
/* Parse string */
*value = text;
return 0;
}
/**
* Parse integer value
*
* @v text Text
* @ret value Integer value
* @ret rc Return status code
*/
int parse_integer ( const char *text, unsigned int *value ) {
char *endp;
/* Sanity check */
assert ( text != NULL );
/* Parse integer */
*value = strtoul ( text, &endp, 0 );
if ( *endp ) {
printf ( "\"%s\": invalid integer value\n", text );
return -EINVAL;
}
return 0;
}
/**
* Parse network device name
*
* @v text Text
* @ret netdev Network device
* @ret rc Return status code
*/
int parse_netdev ( const char *text, struct net_device **netdev ) {
/* Sanity check */
assert ( text != NULL );
/* Find network device */
*netdev = find_netdev ( text );
if ( ! *netdev ) {
printf ( "\"%s\": no such network device\n", text );
return -ENODEV;
}
return 0;
}
/**
* Parse image name
*
* @v text Text
* @ret image Image
* @ret rc Return status code
*/
int parse_image ( const char *text, struct image **image ) {
/* Sanity check */
assert ( text != NULL );
/* Find network device */
*image = find_image ( text );
if ( ! *image ) {
printf ( "\"%s\": no such image\n", text );
return -ENOENT;
}
return 0;
}
/**
* Print command usage message
*
* @v cmd Command descriptor
* @v argv Argument list
*/
void print_usage ( struct command_descriptor *cmd, char **argv ) {
printf ( "Usage:\n\n %s %s\n", argv[0], cmd->usage_description );
}
/**
* Parse command-line options
*
* @v argc Argument count
* @v argv Argument list
* @v cmd Command descriptor
* @v opts Options
* @ret rc Return status code
*/
int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
void *opts ) {
struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
+ 1 /* NUL */ ];
unsigned int shortopt_idx = 0;
int ( * parse ) ( const char *text, void *value );
void *value;
unsigned int i;
unsigned int j;
unsigned int num_args;
int c;
int rc;
/* Construct long and short option lists for getopt_long() */
memset ( longopts, 0, sizeof ( longopts ) );
for ( i = 0 ; i < cmd->num_options ; i++ ) {
longopts[i].name = cmd->options[i].longopt;
longopts[i].has_arg = cmd->options[i].has_arg;
longopts[i].val = cmd->options[i].shortopt;
shortopts[shortopt_idx++] = cmd->options[i].shortopt;
assert ( cmd->options[i].has_arg <= optional_argument );
for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
shortopts[shortopt_idx++] = ':';
}
longopts[i].name = "help";
longopts[i].val = 'h';
shortopts[shortopt_idx++] = 'h';
shortopts[shortopt_idx++] = '\0';
assert ( shortopt_idx <= sizeof ( shortopts ) );
DBGC ( cmd, "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
/* Clear options */
memset ( opts, 0, cmd->len );
/* Parse options */
while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
NULL ) ) >= 0 ) {
switch ( c ) {
case 'h' :
/* Print help */
print_usage ( cmd, argv );
return -ECANCELED_NO_OP;
case '?' :
case ':' :
/* Print usage message */
print_usage ( cmd, argv );
return -EINVAL;
default:
/* Search for an option to parse */
for ( i = 0 ; i < cmd->num_options ; i++ ) {
if ( c != cmd->options[i].shortopt )
continue;
parse = cmd->options[i].parse;
value = ( opts + cmd->options[i].offset );
if ( ( rc = parse ( optarg, value ) ) != 0 )
return rc;
break;
}
assert ( i < cmd->num_options );
}
}
/* Check remaining arguments */
num_args = ( argc - optind );
if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
print_usage ( cmd, argv );
return -ERANGE;
}
return 0;
}
+3
View File
@@ -25,6 +25,9 @@
* at some point. If there's anything obvious or better, not-so-obvious,
* please contact me by e-mail: anselm (AT) hoffmeister (DOT) be *THANKS*
*/
FILE_LICENCE ( GPL2_ONLY );
#include <stdio.h>
#include <pcmcia.h>
#include <i82365.h>
+32 -11
View File
@@ -281,9 +281,9 @@ static struct settings * autovivify_child_settings ( struct settings *parent,
return NULL;
}
memcpy ( new_child->name, name, sizeof ( new_child->name ) );
generic_settings_init ( &new_child->generic, NULL, new_child->name );
generic_settings_init ( &new_child->generic, NULL );
settings = &new_child->generic.settings;
register_settings ( settings, parent );
register_settings ( settings, parent, new_child->name );
return settings;
}
@@ -422,9 +422,11 @@ static void reprioritise_settings ( struct settings *settings ) {
*
* @v settings Settings block
* @v parent Parent settings block, or NULL
* @v name Settings block name
* @ret rc Return status code
*/
int register_settings ( struct settings *settings, struct settings *parent ) {
int register_settings ( struct settings *settings, struct settings *parent,
const char *name ) {
struct settings *old_settings;
/* NULL parent => add to settings root */
@@ -432,6 +434,9 @@ int register_settings ( struct settings *settings, struct settings *parent ) {
if ( parent == NULL )
parent = &settings_root;
/* Apply settings block name */
settings->name = name;
/* Remove any existing settings with the same name */
if ( ( old_settings = find_child_settings ( parent, settings->name ) ))
unregister_settings ( old_settings );
@@ -641,6 +646,29 @@ int fetch_string_setting_copy ( struct settings *settings,
return len;
}
/**
* Fetch value of IPv4 address setting
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v inp IPv4 addresses to fill in
* @v count Maximum number of IPv4 addresses
* @ret len Length of setting, or negative error
*/
int fetch_ipv4_array_setting ( struct settings *settings,
struct setting *setting,
struct in_addr *inp, unsigned int count ) {
int len;
len = fetch_setting ( settings, setting, inp,
( sizeof ( *inp ) * count ) );
if ( len < 0 )
return len;
if ( ( len % sizeof ( *inp ) ) != 0 )
return -ERANGE;
return len;
}
/**
* Fetch value of IPv4 address setting
*
@@ -651,14 +679,7 @@ int fetch_string_setting_copy ( struct settings *settings,
*/
int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
struct in_addr *inp ) {
int len;
len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) );
if ( len < 0 )
return len;
if ( len < ( int ) sizeof ( *inp ) )
return -ERANGE;
return len;
return fetch_ipv4_array_setting ( settings, setting, inp, 1 );
}
/**
+2
View File
@@ -10,6 +10,8 @@
* published by the Free Software Foundation.
*/
FILE_LICENCE ( GPL2_ONLY );
/*
* stupid library routines.. The optimized versions should generally be found
* as inline code in <asm-xx/string.h>
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* AES implementation - this is a small code version. There are much faster
* versions around but they are much larger in size (i.e. they use large
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifndef BIGINT_HEADER
#define BIGINT_HEADER
+2
View File
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* @file crypto.h
*/
+17 -9
View File
@@ -103,13 +103,18 @@ static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
*
* @v ipaddr IP address field
* @v setting Configuration setting
* @v tag DHCP option tag
* @v count Maximum number of IP addresses
*/
static void ibft_set_ipaddr_setting ( struct ibft_ipaddr *ipaddr,
struct setting *setting ) {
struct in_addr in;
fetch_ipv4_setting ( NULL, setting, &in );
ibft_set_ipaddr ( ipaddr, in );
struct setting *setting,
unsigned int count ) {
struct in_addr in[count];
unsigned int i;
fetch_ipv4_array_setting ( NULL, setting, in, count );
for ( i = 0 ; i < count ; i++ ) {
ibft_set_ipaddr ( &ipaddr[i], in[i] );
}
}
/**
@@ -233,12 +238,15 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
/* Extract values from configuration settings */
ibft_set_ipaddr_setting ( &nic->ip_address, &ip_setting );
ibft_set_ipaddr_setting ( &nic->ip_address, &ip_setting, 1 );
DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
ibft_set_ipaddr_setting ( &nic->gateway, &gateway_setting );
ibft_set_ipaddr_setting ( &nic->gateway, &gateway_setting, 1 );
DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
ibft_set_ipaddr_setting ( &nic->dns[0], &dns_setting );
DBG ( "iBFT NIC DNS = %s\n", ibft_ipaddr ( &nic->dns[0] ) );
ibft_set_ipaddr_setting ( &nic->dns[0], &dns_setting,
( sizeof ( nic->dns ) /
sizeof ( nic->dns[0] ) ) );
DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
if ( ( rc = ibft_set_string_setting ( strings, &nic->hostname,
&hostname_setting ) ) != 0 )
return rc;
+17 -19
View File
@@ -64,8 +64,9 @@ static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) {
if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
return ( ( ( uint64_t ) high << 32 ) | low );
} else {
DBG ( "Unhandled 64-bit BAR %08x%08x\n",
high, low );
DBGC ( pci, PCI_FMT " unhandled 64-bit BAR "
"%08x%08x\n",
PCI_ARGS ( pci ), high, low );
return PCI_BASE_ADDRESS_MEM_TYPE_64;
}
}
@@ -148,19 +149,16 @@ void adjust_pci_device ( struct pci_device *pci ) {
new_command = ( pci_command | PCI_COMMAND_MASTER |
PCI_COMMAND_MEM | PCI_COMMAND_IO );
if ( pci_command != new_command ) {
DBG ( "PCI BIOS has not enabled device %02x:%02x.%x! "
"Updating PCI command %04x->%04x\n", pci->bus,
PCI_SLOT ( pci->devfn ), PCI_FUNC ( pci->devfn ),
pci_command, new_command );
DBGC ( pci, PCI_FMT " device not enabled by BIOS! Updating "
"PCI command %04x->%04x\n",
PCI_ARGS ( pci ), pci_command, new_command );
pci_write_config_word ( pci, PCI_COMMAND, new_command );
}
pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency);
if ( pci_latency < 32 ) {
DBG ( "PCI device %02x:%02x.%x latency timer is unreasonably "
"low at %d. Setting to 32.\n", pci->bus,
PCI_SLOT ( pci->devfn ), PCI_FUNC ( pci->devfn ),
pci_latency );
DBGC ( pci, PCI_FMT " latency timer is unreasonably low at "
"%d. Setting to 32.\n", PCI_ARGS ( pci ), pci_latency );
pci_write_config_byte ( pci, PCI_LATENCY_TIMER, 32);
}
}
@@ -180,10 +178,9 @@ static int pci_probe ( struct pci_device *pci ) {
unsigned int i;
int rc;
DBG ( "Adding PCI device %02x:%02x.%x (%04x:%04x mem %lx io %lx "
"irq %d)\n", pci->bus, PCI_SLOT ( pci->devfn ),
PCI_FUNC ( pci->devfn ), pci->vendor, pci->device,
pci->membase, pci->ioaddr, pci->irq );
DBGC ( pci, PCI_FMT " is %04x:%04x mem %lx io %lx irq %d\n",
PCI_ARGS ( pci ), pci->vendor, pci->device, pci->membase,
pci->ioaddr, pci->irq );
for_each_table_entry ( driver, PCI_DRIVERS ) {
for ( i = 0 ; i < driver->id_count ; i++ ) {
@@ -196,16 +193,18 @@ static int pci_probe ( struct pci_device *pci ) {
continue;
pci->driver = driver;
pci->driver_name = id->name;
DBG ( "...using driver %s\n", pci->driver_name );
DBGC ( pci, "...using driver %s\n", pci->driver_name );
if ( ( rc = driver->probe ( pci, id ) ) != 0 ) {
DBG ( "......probe failed\n" );
DBGC ( pci, "......probe failed: %s\n",
strerror ( rc ) );
continue;
}
DBGC ( pci, PCI_FMT " added\n", PCI_ARGS ( pci ) );
return 0;
}
}
DBG ( "...no driver found\n" );
DBGC ( pci, "...no driver found\n" );
return -ENOTTY;
}
@@ -216,8 +215,7 @@ static int pci_probe ( struct pci_device *pci ) {
*/
static void pci_remove ( struct pci_device *pci ) {
pci->driver->remove ( pci );
DBG ( "Removed PCI device %02x:%02x.%x\n", pci->bus,
PCI_SLOT ( pci->devfn ), PCI_FUNC ( pci->devfn ) );
DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
}
/**
+386
View File
@@ -0,0 +1,386 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/isapnp.h>
#include <ipxe/pcivpd.h>
/** @file
*
* PCI Vital Product Data
*
*/
/**
* Initialise PCI Vital Product Data
*
* @v vpd PCI VPD
* @v pci PCI device
* @ret rc Return status code
*/
int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci ) {
/* Initialise structure */
vpd->pci = pci;
pci_vpd_invalidate_cache ( vpd );
/* Locate VPD capability */
vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD );
if ( ! vpd->cap ) {
DBGC ( vpd, PCI_FMT " does not support VPD\n",
PCI_ARGS ( pci ) );
return -ENOTTY;
}
DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n",
PCI_ARGS ( pci ), vpd->cap );
return 0;
}
/**
* Read one dword of PCI Vital Product Data
*
* @v vpd PCI VPD
* @v address Address to read
* @ret data Read data
* @ret rc Return status code
*/
static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address,
uint32_t *data ) {
struct pci_device *pci = vpd->pci;
unsigned int cap = vpd->cap;
unsigned int retries;
uint16_t flag;
/* Return cached value, if present */
if ( pci_vpd_cache_is_valid ( vpd ) &&
( vpd->cache.address == address ) ) {
*data = vpd->cache.data;
return 0;
}
/* Initiate read */
pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address );
/* Wait for read to complete */
for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
/* Check if data is ready */
pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
if ( flag & PCI_VPD_FLAG ) {
/* Read data */
pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ),
data );
DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n",
PCI_ARGS ( pci ), address, htonl ( *data ) );
/* Populate cache */
vpd->cache.address = address;
vpd->cache.data = *data;
return 0;
}
/* Wait 1ms before retrying */
mdelay ( 1 );
}
DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n",
PCI_ARGS ( pci ), address, cap );
return -ETIMEDOUT;
}
/**
* Write one dword of PCI Vital Product Data
*
* @v vpd PCI VPD
* @v address Address to write
* @v data Data to write
* @ret rc Return status code
*/
static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address,
uint32_t data ) {
struct pci_device *pci = vpd->pci;
unsigned int cap = vpd->cap;
unsigned int retries;
uint16_t flag;
/* Invalidate cache */
pci_vpd_invalidate_cache ( vpd );
DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n",
PCI_ARGS ( pci ), address, htonl ( data ) );
/* Write data */
pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data );
/* Initiate write */
pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ),
( address | PCI_VPD_FLAG ) );
/* Wait for write to complete */
for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
/* Check if write has completed */
pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
if ( ! ( flag & PCI_VPD_FLAG ) )
return 0;
/* Wait 1ms before retrying */
mdelay ( 1 );
}
DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n",
PCI_ARGS ( pci ), address, cap );
return -ETIMEDOUT;
}
/**
* Read PCI VPD
*
* @v vpd PCI VPD
* @v address Starting address
* @v buf Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address, void *buf,
size_t len ) {
uint8_t *bytes = buf;
uint32_t data;
size_t skip_len;
unsigned int i;
int rc;
/* Calculate length to skip at start of data */
skip_len = ( address & 0x03 );
/* Read data, a dword at a time */
for ( address &= ~0x03 ; len ; address += 4 ) {
/* Read whole dword */
if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 )
return rc;
/* Copy data to buffer */
for ( i = 4 ; i ; i-- ) {
if ( skip_len ) {
skip_len--;
} else if ( len ) {
*(bytes++) = data;
len--;
}
data = ( ( data << 24 ) | ( data >> 8 ) );
}
}
return 0;
}
/**
* Write PCI VPD
*
* @v vpd PCI VPD
* @v address Starting address
* @v buf Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address, const void *buf,
size_t len ) {
const uint8_t *bytes = buf;
uint32_t data;
size_t skip_len;
unsigned int i;
int rc;
/* Calculate length to skip at start of data */
skip_len = ( address & 0x03 );
/* Write data, a dword at a time */
for ( address &= ~0x03 ; len ; address += 4 ) {
/* Read existing dword, if necessary */
if ( skip_len || ( len <= 0x03 ) ) {
if ( ( rc = pci_vpd_read_dword ( vpd, address,
&data ) ) != 0 )
return rc;
}
/* Copy data from buffer */
for ( i = 4 ; i ; i-- ) {
if ( skip_len ) {
skip_len--;
} else if ( len ) {
data = ( ( data & ~0xff ) | *(bytes++) );
len--;
}
data = ( ( data << 24 ) | ( data >> 8 ) );
}
/* Write whole dword */
if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 )
return rc;
}
return 0;
}
/**
* Dump PCI VPD region (for debugging)
*
* @v vpd PCI VPD
* @v address Starting address
* @v len Length of data
*/
static void pci_vpd_dump ( struct pci_vpd *vpd, unsigned int address,
size_t len ) {
int rc;
/* Do nothing in non-debug builds */
if ( ! DBG_LOG )
return;
/* Read data */
{
char buf[len];
if ( ( rc = pci_vpd_read ( vpd, address, buf,
sizeof ( buf ) ) ) != 0 )
return;
DBGC_HDA ( vpd, address, buf, sizeof ( buf ) );
}
}
/**
* Locate PCI VPD tag
*
* @v vpd PCI VPD
* @v tag ISAPnP tag
* @ret address Address of tag body
* @ret len Length of tag body
* @ret rc Return status code
*/
static int pci_vpd_find_tag ( struct pci_vpd *vpd, unsigned int tag,
unsigned int *address, size_t *len ) {
uint8_t read_tag;
uint16_t read_len;
int rc;
/* Scan through tags looking for a match */
*address = 0;
do {
/* Read tag byte */
if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag,
sizeof ( read_tag ) ) ) != 0 )
return rc;
/* Extract tag and length */
if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) {
if ( ( rc = pci_vpd_read ( vpd, *address, &read_len,
sizeof ( read_len ) ) ) != 0)
return rc;
*address += sizeof ( read_len );
read_len = le16_to_cpu ( read_len );
read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag );
} else {
read_len = ISAPNP_SMALL_TAG_LEN ( read_tag );
read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag );
}
/* Check for tag match */
if ( tag == read_tag ) {
*len = read_len;
DBGC ( vpd, PCI_FMT " VPD tag %02x is at "
"[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag,
*address, ( *address + *len ) );
return 0;
}
/* Move to next tag */
*address += read_len;
} while ( read_tag != ISAPNP_TAG_END );
DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n",
PCI_ARGS ( vpd->pci ), tag );
return -ENOENT;
}
/**
* Locate PCI VPD field
*
* @v vpd PCI VPD
* @v field VPD field descriptor
* @ret address Address of field body
* @ret len Length of field body
* @ret rc Return status code
*/
int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
unsigned int *address, size_t *len ) {
struct pci_vpd_field read_field;
int rc;
/* Locate containing tag */
if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ),
address, len ) ) != 0 )
return rc;
/* Return immediately if we are searching for a whole-tag field */
if ( ! PCI_VPD_KEYWORD ( field ) ) {
pci_vpd_dump ( vpd, *address, *len );
return 0;
}
/* Scan through fields looking for a match */
while ( *len >= sizeof ( read_field ) ) {
/* Read field header */
if ( ( rc = pci_vpd_read ( vpd, *address, &read_field,
sizeof ( read_field ) ) ) != 0 )
return rc;
*address += sizeof ( read_field );
*len -= sizeof ( read_field );
/* Check for keyword match */
if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) {
*len = read_field.len;
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
" is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ),
*address, ( *address + *len ) );
pci_vpd_dump ( vpd, *address, *len );
return 0;
}
/* Move to next field */
if ( read_field.len > *len )
break;
*address += read_field.len;
*len -= read_field.len;
}
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n",
PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
return -ENOENT;
}
+2
View File
@@ -14,6 +14,8 @@
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include "etherboot.h"
#include "ipxe/io.h"
#include "ipxe/virtio-ring.h"
+22 -5
View File
@@ -38,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/ib_smc.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
#include <ipxe/fcoe.h>
#include <ipxe/vlan.h>
#include "hermon.h"
/**
@@ -1647,6 +1649,7 @@ static int hermon_complete ( struct ib_device *ibdev,
len = MLX_GET ( &cqe->normal, byte_cnt );
assert ( len <= iob_tailroom ( iobuf ) );
iob_put ( iobuf, len );
memset ( &recv_av, 0, sizeof ( recv_av ) );
switch ( qp->type ) {
case IB_QPT_SMI:
case IB_QPT_GSI:
@@ -1656,7 +1659,6 @@ static int hermon_complete ( struct ib_device *ibdev,
iob_pull ( iobuf, sizeof ( *grh ) );
/* Construct address vector */
av = &recv_av;
memset ( av, 0, sizeof ( *av ) );
av->qpn = MLX_GET ( &cqe->normal, srq_rqpn );
av->lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
av->sl = MLX_GET ( &cqe->normal, sl );
@@ -1667,7 +1669,10 @@ static int hermon_complete ( struct ib_device *ibdev,
av = &qp->av;
break;
case IB_QPT_ETH:
av = NULL;
/* Construct address vector */
av = &recv_av;
av->vlan_present = MLX_GET ( &cqe->normal, vlan );
av->vlan = MLX_GET ( &cqe->normal, vid );
break;
default:
assert ( 0 );
@@ -2274,9 +2279,19 @@ static void hermon_eth_complete_send ( struct ib_device *ibdev __unused,
*/
static void hermon_eth_complete_recv ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
struct ib_address_vector *av __unused,
struct ib_address_vector *av,
struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct net_device *vlan;
/* Find VLAN device, if applicable */
if ( av->vlan_present ) {
if ( ( vlan = vlan_find ( netdev, av->vlan ) ) != NULL ) {
netdev = vlan;
} else if ( rc == 0 ) {
rc = -ENODEV;
}
}
/* Hand off to network layer */
if ( rc == 0 ) {
@@ -2368,8 +2383,10 @@ static int hermon_eth_open ( struct net_device *netdev ) {
v_pptx, 1 );
MLX_FILL_1 ( &set_port.general, 1,
mtu, ( ETH_FRAME_LEN + 40 /* Used by card */ ) );
MLX_FILL_1 ( &set_port.general, 2, pptx, 1 );
MLX_FILL_1 ( &set_port.general, 3, pprx, 1 );
MLX_FILL_1 ( &set_port.general, 2,
pfctx, ( 1 << FCOE_VLAN_PRIORITY ) );
MLX_FILL_1 ( &set_port.general, 3,
pfcrx, ( 1 << FCOE_VLAN_PRIORITY ) );
if ( ( rc = hermon_cmd_set_port ( hermon, 1,
( HERMON_SET_PORT_GENERAL_PARAM |
ibdev->port ),
+1 -1
View File
@@ -211,7 +211,7 @@ struct hermonprm_sense_port_st {
pseudo_bit_t reserved0[0x00020];
/* -------------- */
pseudo_bit_t port_type[0x00002];
pseudo_bit_t reserved1[0x00018];
pseudo_bit_t reserved1[0x0001e];
} __attribute__ (( packed ));
struct hermonprm_set_port_ib_st {
+2
View File
@@ -22,6 +22,8 @@
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifndef _ATL1E_H_
#define _ATL1E_H_
+375
View File
@@ -0,0 +1,375 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
/* Linux PRO/1000 Ethernet Driver main header file */
#ifndef _IGBVF_H_
#define _IGBVF_H_
#include "igbvf_vf.h"
/* Forward declarations */
struct igbvf_info;
struct igbvf_adapter;
/* Interrupt defines */
#define IGBVF_START_ITR 648 /* ~6000 ints/sec */
/* Tx/Rx descriptor defines */
#define IGBVF_DEFAULT_TXD 256
#define IGBVF_MAX_TXD 4096
#define IGBVF_MIN_TXD 80
#define IGBVF_DEFAULT_RXD 256
#define IGBVF_MAX_RXD 4096
#define IGBVF_MIN_RXD 80
#define IGBVF_MIN_ITR_USECS 10 /* 100000 irq/sec */
#define IGBVF_MAX_ITR_USECS 10000 /* 100 irq/sec */
/* RX descriptor control thresholds.
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
* descriptors available in its onboard memory.
* Setting this to 0 disables RX descriptor prefetch.
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
* available in host memory.
* If PTHRESH is 0, this should also be 0.
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
* descriptors until either it has this many to write back, or the
* ITR timer expires.
*/
#define IGBVF_RX_PTHRESH 16
#define IGBVF_RX_HTHRESH 8
#define IGBVF_RX_WTHRESH 1
#define IGBVF_TX_PTHRESH 8
#define IGBVF_TX_HTHRESH 1
#define IGBVF_TX_WTHRESH 1
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
#define IGBVF_FC_PAUSE_TIME 0x0680 /* 858 usec */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define IGBVF_TX_QUEUE_WAKE 32
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IGBVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define IGBVF_EEPROM_APME 0x0400
#define IGBVF_MNG_VLAN_NONE (-1)
enum igbvf_boards {
board_vf,
};
struct igbvf_queue_stats {
u64 packets;
u64 bytes;
};
/*
* wrappers around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer
*/
struct igbvf_buffer {
dma_addr_t dma;
dma_addr_t page_dma;
struct sk_buff *skb;
union {
/* Tx */
struct {
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
};
/* Rx */
struct {
struct page *page;
unsigned int page_offset;
};
};
struct page *page;
};
struct igbvf_ring {
struct igbvf_adapter *adapter; /* backlink */
void *desc; /* pointer to ring memory */
dma_addr_t dma; /* phys address of ring */
unsigned int size; /* length of ring in bytes */
unsigned int count; /* number of desc. in ring */
u16 next_to_use;
u16 next_to_clean;
u16 head;
u16 tail;
/* array of buffer information structs */
struct igbvf_buffer *buffer_info;
#if 0
struct napi_struct napi;
char name[IFNAMSIZ + 5];
#endif
u32 eims_value;
u32 itr_val;
u16 itr_register;
int set_itr;
struct sk_buff *rx_skb_top;
struct igbvf_queue_stats stats;
};
/* board specific private data structure */
struct igbvf_adapter {
#if 0
struct timer_list watchdog_timer;
struct timer_list blink_timer;
struct work_struct reset_task;
struct work_struct watchdog_task;
const struct igbvf_info *ei;
struct vlan_group *vlgrp;
u32 bd_number;
u32 rx_buffer_len;
u32 polling_interval;
u16 mng_vlan_id;
u16 link_speed;
u16 link_duplex;
spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
/* track device up/down/testing state */
unsigned long state;
/* Interrupt Throttle Rate */
u32 itr;
u32 itr_setting;
u16 tx_itr;
u16 rx_itr;
/*
* Tx
*/
struct igbvf_ring *tx_ring /* One per active queue */
____cacheline_aligned_in_smp;
unsigned long tx_queue_len;
unsigned int restart_queue;
u32 txd_cmd;
bool detect_tx_hung;
u8 tx_timeout_factor;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
unsigned int total_rx_packets;
/* Tx stats */
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
u32 tx_fifo_size;
u32 tx_dma_failed;
/*
* Rx
*/
struct igbvf_ring *rx_ring;
/* Rx stats */
u64 hw_csum_err;
u64 hw_csum_good;
u64 rx_hdr_split;
u32 alloc_rx_buff_failed;
u32 rx_dma_failed;
unsigned int rx_ps_hdr_size;
u32 max_frame_size;
u32 min_frame_size;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
spinlock_t stats_lock; /* prevent concurrent stats updates */
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
/* The VF counters don't clear on read so we have to get a base
* count on driver start up and always subtract that base on
* on the first update, thus the flag..
*/
struct e1000_vf_stats stats;
u64 zero_base;
struct igbvf_ring test_tx_ring;
struct igbvf_ring test_rx_ring;
u32 test_icr;
u32 msg_enable;
struct msix_entry *msix_entries;
int int_mode;
u32 eims_enable_mask;
u32 eims_other;
u32 int_counter0;
u32 int_counter1;
u32 eeprom_wol;
u32 wol;
u32 pba;
bool fc_autoneg;
unsigned long led_status;
unsigned int flags;
unsigned long last_reset;
u32 *config_space;
#endif
/* OS defined structs */
struct net_device *netdev;
struct pci_device *pdev;
struct net_device_stats net_stats;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
u32 min_frame_size;
u32 max_frame_size;
u32 max_hw_frame_size;
#define NUM_TX_DESC 8
#define NUM_RX_DESC 8
struct io_buffer *tx_iobuf[NUM_TX_DESC];
struct io_buffer *rx_iobuf[NUM_RX_DESC];
union e1000_adv_tx_desc *tx_base;
union e1000_adv_rx_desc *rx_base;
uint32_t tx_ring_size;
uint32_t rx_ring_size;
uint32_t tx_head;
uint32_t tx_tail;
uint32_t tx_fill_ctr;
uint32_t rx_curr;
uint32_t ioaddr;
uint32_t irqno;
uint32_t tx_int_delay;
uint32_t tx_abs_int_delay;
uint32_t txd_cmd;
};
struct igbvf_info {
enum e1000_mac_type mac;
unsigned int flags;
u32 pba;
void (*init_ops)(struct e1000_hw *);
s32 (*get_variants)(struct igbvf_adapter *);
};
/* hardware capability, feature, and workaround flags */
#define IGBVF_FLAG_RX_CSUM_DISABLED (1 << 0)
#define IGBVF_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1)
#define IGBVF_RX_DESC_ADV(R, i) \
(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
#define IGBVF_TX_DESC_ADV(R, i) \
(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
#define IGBVF_TX_CTXTDESC_ADV(R, i) \
(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
enum igbvf_state_t {
__IGBVF_TESTING,
__IGBVF_RESETTING,
__IGBVF_DOWN
};
enum latency_range {
lowest_latency = 0,
low_latency = 1,
bulk_latency = 2,
latency_invalid = 255
};
extern char igbvf_driver_name[];
extern const char igbvf_driver_version[];
extern void igbvf_check_options(struct igbvf_adapter *adapter);
extern void igbvf_set_ethtool_ops(struct net_device *netdev);
#ifdef ETHTOOL_OPS_COMPAT
extern int ethtool_ioctl(struct ifreq *ifr);
#endif
extern int igbvf_up(struct igbvf_adapter *adapter);
extern void igbvf_down(struct igbvf_adapter *adapter);
extern void igbvf_reinit_locked(struct igbvf_adapter *adapter);
extern void igbvf_reset(struct igbvf_adapter *adapter);
extern int igbvf_setup_rx_resources(struct igbvf_adapter *adapter);
extern int igbvf_setup_tx_resources(struct igbvf_adapter *adapter);
extern void igbvf_free_rx_resources(struct igbvf_adapter *adapter);
extern void igbvf_free_tx_resources(struct igbvf_adapter *adapter);
extern void igbvf_update_stats(struct igbvf_adapter *adapter);
extern void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter);
extern void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter);
extern unsigned int copybreak;
static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
{
return readl(hw->hw_addr + reg);
}
static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
{
writel(val, hw->hw_addr + reg);
}
#define er32(reg) E1000_READ_REG(hw, E1000_##reg)
#define ew32(reg,val) E1000_WRITE_REG(hw, E1000_##reg, (val))
#define e1e_flush() er32(STATUS)
#endif /* _IGBVF_H_ */
File diff suppressed because it is too large Load Diff
+955
View File
@@ -0,0 +1,955 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 2009 Intel Corporation.
Copyright(c) 2010 Eric Keller <ekeller@princeton.edu>
Copyright(c) 2010 Red Hat Inc.
Alex Williamson <alex.williamson@redhat.com>
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#include "igbvf.h"
/**
* igbvf_setup_tx_resources - allocate Tx resources (Descriptors)
*
* @v adapter e1000 private structure
*
* @ret rc Returns 0 on success, negative on failure
**/
int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter )
{
DBG ( "igbvf_setup_tx_resources\n" );
/* Allocate transmit descriptor ring memory.
It must not cross a 64K boundary because of hardware errata #23
so we use malloc_dma() requesting a 128 byte block that is
128 byte aligned. This should guarantee that the memory
allocated will not cross a 64K boundary, because 128 is an
even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
allocations of 128 bytes on a 128 byte boundary will not
cross 64K bytes.
*/
adapter->tx_base =
malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
if ( ! adapter->tx_base ) {
return -ENOMEM;
}
memset ( adapter->tx_base, 0, adapter->tx_ring_size );
DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
return 0;
}
/**
* igbvf_free_tx_resources - Free Tx Resources per Queue
* @adapter: board private structure
*
* Free all transmit software resources
**/
void igbvf_free_tx_resources ( struct igbvf_adapter *adapter )
{
DBG ( "igbvf_free_tx_resources\n" );
free_dma ( adapter->tx_base, adapter->tx_ring_size );
}
/**
* igbvf_free_rx_resources - Free Rx Resources
* @adapter: board private structure
*
* Free all receive software resources
**/
void igbvf_free_rx_resources ( struct igbvf_adapter *adapter )
{
int i;
DBG ( "igbvf_free_rx_resources\n" );
free_dma ( adapter->rx_base, adapter->rx_ring_size );
for ( i = 0; i < NUM_RX_DESC; i++ ) {
free_iob ( adapter->rx_iobuf[i] );
}
}
/**
* igbvf_refill_rx_ring - allocate Rx io_buffers
*
* @v adapter e1000 private structure
*
* @ret rc Returns 0 on success, negative on failure
**/
static int igbvf_refill_rx_ring ( struct igbvf_adapter *adapter )
{
int i, rx_curr;
int rc = 0;
union e1000_adv_rx_desc *rx_curr_desc;
struct e1000_hw *hw = &adapter->hw;
struct io_buffer *iob;
DBGP ("igbvf_refill_rx_ring\n");
for ( i = 0; i < NUM_RX_DESC; i++ ) {
rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
rx_curr_desc = adapter->rx_base + rx_curr;
if ( rx_curr_desc->wb.upper.status_error & E1000_RXD_STAT_DD )
continue;
if ( adapter->rx_iobuf[rx_curr] != NULL )
continue;
DBG2 ( "Refilling rx desc %d\n", rx_curr );
iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
adapter->rx_iobuf[rx_curr] = iob;
rx_curr_desc->wb.upper.status_error = 0;
if ( ! iob ) {
DBG ( "alloc_iob failed\n" );
rc = -ENOMEM;
break;
} else {
rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
rx_curr_desc->read.hdr_addr = 0;
ew32 ( RDT(0), rx_curr );
}
}
return rc;
}
/**
* igbvf_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
**/
static void igbvf_irq_disable ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
ew32 ( EIMC, ~0 );
}
/**
* igbvf_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
**/
static void igbvf_irq_enable ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
ew32 ( EIAC, IMS_ENABLE_MASK );
ew32 ( EIAM, IMS_ENABLE_MASK );
ew32 ( EIMS, IMS_ENABLE_MASK );
}
/**
* igbvf_irq - enable or Disable interrupts
*
* @v adapter e1000 adapter
* @v action requested interrupt action
**/
static void igbvf_irq ( struct net_device *netdev, int enable )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
DBG ( "igbvf_irq\n" );
if ( enable ) {
igbvf_irq_enable ( adapter );
} else {
igbvf_irq_disable ( adapter );
}
}
/**
* igbvf_process_tx_packets - process transmitted packets
*
* @v netdev network interface device structure
**/
static void igbvf_process_tx_packets ( struct net_device *netdev )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
uint32_t i;
uint32_t tx_status;
union e1000_adv_tx_desc *tx_curr_desc;
/* Check status of transmitted packets
*/
DBGP ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
adapter->tx_tail );
while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
tx_curr_desc = ( void * ) ( adapter->tx_base ) +
( i * sizeof ( *adapter->tx_base ) );
tx_status = tx_curr_desc->wb.status;
DBG ( " tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
DBG ( " tx_status = %#08x\n", tx_status );
/* if the packet at tx_head is not owned by hardware it is for us */
if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
break;
DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
adapter->tx_head, adapter->tx_tail, tx_status );
netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
DBG ( "Success transmitting packet, tx_status: %#08x\n",
tx_status );
/* Decrement count of used descriptors, clear this descriptor
*/
adapter->tx_fill_ctr--;
memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
}
}
/**
* igbvf_process_rx_packets - process received packets
*
* @v netdev network interface device structure
**/
static void igbvf_process_rx_packets ( struct net_device *netdev )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
struct e1000_hw *hw = &adapter->hw;
uint32_t i;
uint32_t rx_status;
uint32_t rx_len;
uint32_t rx_err;
union e1000_adv_rx_desc *rx_curr_desc;
DBGP ( "igbvf_process_rx_packets\n" );
/* Process received packets
*/
while ( 1 ) {
i = adapter->rx_curr;
rx_curr_desc = ( void * ) ( adapter->rx_base ) +
( i * sizeof ( *adapter->rx_base ) );
rx_status = rx_curr_desc->wb.upper.status_error;
DBG2 ( "Before DD Check RX_status: %#08x, rx_curr: %d\n",
rx_status, i );
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
break;
if ( adapter->rx_iobuf[i] == NULL )
break;
DBG ( "E1000_RCTL = %#08x\n", er32 (RCTL) );
rx_len = rx_curr_desc->wb.upper.length;
DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n",
i, rx_status, rx_len );
rx_err = rx_status;
iob_put ( adapter->rx_iobuf[i], rx_len );
if ( rx_err & E1000_RXDEXT_ERR_FRAME_ERR_MASK ) {
netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
DBG ( "igbvf_process_rx_packets: Corrupted packet received!"
" rx_err: %#08x\n", rx_err );
} else {
/* Add this packet to the receive queue. */
netdev_rx ( netdev, adapter->rx_iobuf[i] );
}
adapter->rx_iobuf[i] = NULL;
memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
}
}
/**
* igbvf_poll - Poll for received packets
*
* @v netdev Network device
*/
static void igbvf_poll ( struct net_device *netdev )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
uint32_t rx_status;
union e1000_adv_rx_desc *rx_curr_desc;
DBGP ( "igbvf_poll\n" );
rx_curr_desc = ( void * ) ( adapter->rx_base ) +
( adapter->rx_curr * sizeof ( *adapter->rx_base ) );
rx_status = rx_curr_desc->wb.upper.status_error;
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
return;
igbvf_process_tx_packets ( netdev );
igbvf_process_rx_packets ( netdev );
igbvf_refill_rx_ring ( adapter );
}
/**
* igbvf_config_collision_dist_generic - Configure collision distance
* @hw: pointer to the HW structure
*
* Configures the collision distance to the default value and is used
* during link setup. Currently no func pointer exists and all
* implementations are handled in the generic version of this function.
**/
void igbvf_config_collision_dist ( struct e1000_hw *hw )
{
u32 tctl;
DBG ("igbvf_config_collision_dist");
tctl = er32 (TCTL);
tctl &= ~E1000_TCTL_COLD;
tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
ew32 (TCTL, tctl);
e1e_flush();
}
/**
* igbvf_configure_tx - Configure Transmit Unit after Reset
* @adapter: board private structure
*
* Configure the Tx unit of the MAC after a reset.
**/
static void igbvf_configure_tx ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
u32 tctl, txdctl;
DBG ( "igbvf_configure_tx\n" );
/* disable transmits while setting up the descriptors */
tctl = er32 ( TCTL );
ew32 ( TCTL, tctl & ~E1000_TCTL_EN );
e1e_flush();
mdelay (10);
ew32 ( TDBAH(0), 0 );
ew32 ( TDBAL(0), virt_to_bus ( adapter->tx_base ) );
ew32 ( TDLEN(0), adapter->tx_ring_size );
DBG ( "E1000_TDBAL(0): %#08x\n", er32 ( TDBAL(0) ) );
DBG ( "E1000_TDLEN(0): %d\n", er32 ( TDLEN(0) ) );
/* Setup the HW Tx Head and Tail descriptor pointers */
ew32 ( TDH(0), 0 );
ew32 ( TDT(0), 0 );
adapter->tx_head = 0;
adapter->tx_tail = 0;
adapter->tx_fill_ctr = 0;
txdctl = er32(TXDCTL(0));
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
ew32 ( TXDCTL(0), txdctl );
txdctl = er32 ( TXDCTL(0) );
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
ew32 ( TXDCTL(0), txdctl );
/* Setup Transmit Descriptor Settings for eop descriptor */
adapter->txd_cmd = E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_IFCS;
/* Advanced descriptor */
adapter->txd_cmd |= E1000_ADVTXD_DCMD_DEXT;
/* (not part of cmd, but in same 32 bit word...) */
adapter->txd_cmd |= E1000_ADVTXD_DTYP_DATA;
/* enable Report Status bit */
adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS;
/* Program the Transmit Control Register */
tctl &= ~E1000_TCTL_CT;
tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
igbvf_config_collision_dist ( hw );
/* Enable transmits */
tctl |= E1000_TCTL_EN;
ew32(TCTL, tctl);
e1e_flush();
}
/* igbvf_reset - bring the hardware into a known good state
*
* This function boots the hardware and enables some settings that
* require a configuration cycle of the hardware - those cannot be
* set/changed during runtime. After reset the device needs to be
* properly configured for Rx, Tx etc.
*/
void igbvf_reset ( struct igbvf_adapter *adapter )
{
struct e1000_mac_info *mac = &adapter->hw.mac;
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
/* Allow time for pending master requests to run */
if ( mac->ops.reset_hw(hw) )
DBG ("PF still resetting\n");
mac->ops.init_hw ( hw );
if ( is_valid_ether_addr(adapter->hw.mac.addr) ) {
memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
}
}
extern void igbvf_init_function_pointers_vf(struct e1000_hw *hw);
/**
* igbvf_sw_init - Initialize general software structures (struct igbvf_adapter)
* @adapter: board private structure to initialize
*
* igbvf_sw_init initializes the Adapter private data structure.
* Fields are initialized based on PCI device information and
* OS network device settings (MTU size).
**/
static int __devinit igbvf_sw_init ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
struct pci_device *pdev = adapter->pdev;
int rc;
/* PCI config space info */
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
pci_read_config_byte ( pdev, PCI_REVISION_ID, &hw->revision_id );
pci_read_config_word ( pdev, PCI_COMMAND, &hw->bus.pci_cmd_word );
adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
/* Set various function pointers */
igbvf_init_function_pointers_vf ( &adapter->hw );
rc = adapter->hw.mac.ops.init_params ( &adapter->hw );
if (rc) {
DBG ("hw.mac.ops.init_params(&adapter->hw) Failure\n");
return rc;
}
rc = adapter->hw.mbx.ops.init_params ( &adapter->hw );
if (rc) {
DBG ("hw.mbx.ops.init_params(&adapter->hw) Failure\n");
return rc;
}
/* Explicitly disable IRQ since the NIC can be in any state. */
igbvf_irq_disable ( adapter );
return 0;
}
/**
* igbvf_setup_srrctl - configure the receive control registers
* @adapter: Board private structure
**/
static void igbvf_setup_srrctl ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
u32 srrctl = 0;
DBG ( "igbvf_setup_srrctl\n" );
srrctl &= ~(E1000_SRRCTL_DESCTYPE_MASK |
E1000_SRRCTL_BSIZEHDR_MASK |
E1000_SRRCTL_BSIZEPKT_MASK);
/* Enable queue drop to avoid head of line blocking */
srrctl |= E1000_SRRCTL_DROP_EN;
/* Setup buffer sizes */
srrctl |= 2048 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
ew32 ( SRRCTL(0), srrctl );
}
/**
* igbvf_configure_rx - Configure 8254x Receive Unit after Reset
* @adapter: board private structure
*
* Configure the Rx unit of the MAC after a reset.
**/
static void igbvf_configure_rx ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
u32 rxdctl;
DBG ( "igbvf_configure_rx\n" );
/* disable receives */
rxdctl = er32 ( RXDCTL(0) );
ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
msleep ( 10 );
/*
* Setup the HW Rx Head and Tail Descriptor Pointers and
* the Base and Length of the Rx Descriptor Ring
*/
ew32 ( RDBAL(0), virt_to_bus (adapter->rx_base) );
ew32 ( RDBAH(0), 0 );
ew32 ( RDLEN(0), adapter->rx_ring_size );
adapter->rx_curr = 0;
ew32 ( RDH(0), 0 );
ew32 ( RDT(0), 0 );
rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
rxdctl &= 0xFFF00000;
rxdctl |= IGBVF_RX_PTHRESH;
rxdctl |= IGBVF_RX_HTHRESH << 8;
rxdctl |= IGBVF_RX_WTHRESH << 16;
igbvf_rlpml_set_vf ( hw, adapter->max_frame_size );
/* enable receives */
ew32 ( RXDCTL(0), rxdctl );
ew32 ( RDT(0), NUM_RX_DESC );
}
/**
* igbvf_setup_rx_resources - allocate Rx resources (Descriptors)
*
* @v adapter e1000 private structure
**/
int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter )
{
int i;
union e1000_adv_rx_desc *rx_curr_desc;
struct io_buffer *iob;
DBG ( "igbvf_setup_rx_resources\n" );
/* Allocate receive descriptor ring memory.
It must not cross a 64K boundary because of hardware errata
*/
adapter->rx_base =
malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
if ( ! adapter->rx_base ) {
return -ENOMEM;
}
memset ( adapter->rx_base, 0, adapter->rx_ring_size );
for ( i = 0; i < NUM_RX_DESC; i++ ) {
rx_curr_desc = adapter->rx_base + i;
iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
adapter->rx_iobuf[i] = iob;
rx_curr_desc->wb.upper.status_error = 0;
if ( ! iob ) {
DBG ( "alloc_iob failed\n" );
return -ENOMEM;
} else {
rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
rx_curr_desc->read.hdr_addr = 0;
}
}
return 0;
}
/**
* igbvf_open - Called when a network interface is made active
* @netdev: network interface device structure
*
* Returns 0 on success, negative value on failure
*
* The open entry point is called when a network interface is made
* active by the system (IFF_UP). At this point all resources needed
* for transmit and receive operations are allocated, the interrupt
* handler is registered with the OS, the watchdog timer is started,
* and the stack is notified that the interface is ready.
**/
static int igbvf_open ( struct net_device *netdev )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
int err;
DBG ("igbvf_open\n");
/* allocate transmit descriptors */
err = igbvf_setup_tx_resources ( adapter );
if (err) {
DBG ( "Error setting up TX resources!\n" );
goto err_setup_tx;
}
igbvf_configure_tx ( adapter );
igbvf_setup_srrctl( adapter );
err = igbvf_setup_rx_resources( adapter );
if (err) {
DBG ( "Error setting up RX resources!\n" );
goto err_setup_rx;
}
igbvf_configure_rx ( adapter );
return 0;
err_setup_rx:
DBG ( "err_setup_rx\n" );
igbvf_free_tx_resources ( adapter );
return err;
err_setup_tx:
DBG ( "err_setup_tx\n" );
igbvf_reset ( adapter );
return err;
}
/**
* igbvf_close - Disables a network interface
* @netdev: network interface device structure
*
* Returns 0, this is not allowed to fail
*
* The close entry point is called when an interface is de-activated
* by the OS. The hardware is still under the drivers control, but
* needs to be disabled. A global MAC reset is issued to stop the
* hardware, and all transmit and receive resources are freed.
**/
static void igbvf_close ( struct net_device *netdev )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
struct e1000_hw *hw = &adapter->hw;
uint32_t rxdctl;
uint32_t icr;
DBG ( "igbvf_close\n" );
icr = er32(EICR);
igbvf_irq_disable ( adapter );
/* disable receives */
rxdctl = er32 ( RXDCTL(0) );
ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
mdelay ( 10 );
igbvf_reset ( adapter );
igbvf_free_tx_resources( adapter );
igbvf_free_rx_resources( adapter );
}
/**
* igbvf_transmit - Transmit a packet
*
* @v netdev Network device
* @v iobuf I/O buffer
*
* @ret rc Returns 0 on success, negative on failure
*/
static int igbvf_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
{
struct igbvf_adapter *adapter = netdev_priv ( netdev );
struct e1000_hw *hw = &adapter->hw;
uint32_t tx_curr = adapter->tx_tail;
union e1000_adv_tx_desc *tx_curr_desc;
DBGP ("igbvf_transmit\n");
if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
DBG ("TX overflow\n");
return -ENOBUFS;
}
/* Save pointer to iobuf we have been given to transmit,
netdev_tx_complete() will need it later
*/
adapter->tx_iobuf[tx_curr] = iobuf;
tx_curr_desc = ( void * ) ( adapter->tx_base ) +
( tx_curr * sizeof ( *adapter->tx_base ) );
DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
/* Add the packet to TX ring
*/
tx_curr_desc->read.buffer_addr = virt_to_bus ( iobuf->data );
tx_curr_desc->read.cmd_type_len = adapter->txd_cmd |(iob_len ( iobuf )) ;
// minus hdr_len ????
tx_curr_desc->read.olinfo_status = ((iob_len ( iobuf )) << E1000_ADVTXD_PAYLEN_SHIFT);
DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
/* Point to next free descriptor */
adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
adapter->tx_fill_ctr++;
/* Write new tail to NIC, making packet available for transmit
*/
ew32 ( TDT(0), adapter->tx_tail );
e1e_flush ();
return 0;
}
/** igbvf net device operations */
static struct net_device_operations igbvf_operations = {
.open = igbvf_open,
.close = igbvf_close,
.transmit = igbvf_transmit,
.poll = igbvf_poll,
.irq = igbvf_irq,
};
/**
* igbvf_get_hw_control - get control of the h/w from f/w
* @adapter: address of board private structure
*
* igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
* For ASF and Pass Through versions of f/w this means that
* the driver is loaded.
*
**/
void igbvf_get_hw_control ( struct igbvf_adapter *adapter )
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_ext;
/* Let firmware know the driver has taken over */
ctrl_ext = er32 ( CTRL_EXT );
ew32 ( CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD );
}
/**
* igbvf_probe - Device Initialization Routine
* @pdev: PCI device information struct
* @ent: entry in igbvf_pci_tbl
*
* Returns 0 on success, negative on failure
*
* igbvf_probe initializes an adapter identified by a pci_dev structure.
* The OS initialization, configuring of the adapter private structure,
* and a hardware reset occur.
**/
int igbvf_probe ( struct pci_device *pdev,
const struct pci_device_id *ent __unused )
{
int err;
struct net_device *netdev;
struct igbvf_adapter *adapter;
unsigned long mmio_start, mmio_len;
struct e1000_hw *hw;
DBG ( "igbvf_probe\n" );
err = -ENOMEM;
/* Allocate net device ( also allocates memory for netdev->priv
and makes netdev-priv point to it ) */
netdev = alloc_etherdev ( sizeof ( struct igbvf_adapter ) );
if ( ! netdev )
goto err_alloc_etherdev;
/* Associate igbvf-specific network operations operations with
* generic network device layer */
netdev_init ( netdev, &igbvf_operations );
/* Associate this network device with given PCI device */
pci_set_drvdata ( pdev, netdev );
netdev->dev = &pdev->dev;
/* Initialize driver private storage */
adapter = netdev_priv ( netdev );
memset ( adapter, 0, ( sizeof ( *adapter ) ) );
adapter->pdev = pdev;
adapter->ioaddr = pdev->ioaddr;
adapter->hw.io_base = pdev->ioaddr;
hw = &adapter->hw;
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
adapter->irqno = pdev->irq;
adapter->netdev = netdev;
adapter->hw.back = adapter;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
/* Fix up PCI device */
adjust_pci_device ( pdev );
err = -EIO;
mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
mmio_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_0 );
DBG ( "mmio_start: %#08lx\n", mmio_start );
DBG ( "mmio_len: %#08lx\n", mmio_len );
adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
if ( ! adapter->hw.hw_addr ) {
DBG ( "err_ioremap\n" );
goto err_ioremap;
}
/* setup adapter struct */
err = igbvf_sw_init ( adapter );
if (err) {
DBG ( "err_sw_init\n" );
goto err_sw_init;
}
/* reset the controller to put the device in a known good state */
err = hw->mac.ops.reset_hw ( hw );
if ( err ) {
DBG ("PF still in reset state, assigning new address\n");
netdev->hw_addr[0] = 0x21;
netdev->hw_addr[1] = 0x21;
netdev->hw_addr[2] = 0x21;
netdev->hw_addr[3] = 0x21;
netdev->hw_addr[4] = 0x21;
netdev->hw_addr[5] = 0x21;
netdev->hw_addr[6] = 0x21;
} else {
err = hw->mac.ops.read_mac_addr(hw);
if (err) {
DBG ("Error reading MAC address\n");
goto err_hw_init;
}
}
memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
if ( ! is_valid_ether_addr( netdev->hw_addr ) ) {
DBG ("Invalid MAC Address: "
"%02x:%02x:%02x:%02x:%02x:%02x\n",
netdev->hw_addr[0], netdev->hw_addr[1],
netdev->hw_addr[2], netdev->hw_addr[3],
netdev->hw_addr[4], netdev->hw_addr[5]);
err = -EIO;
goto err_hw_init;
}
/* reset the hardware with the new settings */
igbvf_reset ( adapter );
/* let the f/w know that the h/w is now under the control of the
* driver. */
igbvf_get_hw_control ( adapter );
/* Mark as link up; we don't yet handle link state */
netdev_link_up ( netdev );
if ( ( err = register_netdev ( netdev ) ) != 0) {
DBG ( "err_register\n" );
goto err_register;
}
DBG ("igbvf_probe_succeeded\n");
return 0;
err_register:
err_hw_init:
err_sw_init:
iounmap ( adapter->hw.hw_addr );
err_ioremap:
netdev_put ( netdev );
err_alloc_etherdev:
return err;
}
/**
* igbvf_remove - Device Removal Routine
* @pdev: PCI device information struct
*
* igbvf_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device. The could be caused by a
* Hot-Plug event, or because the driver is going to be removed from
* memory.
**/
void igbvf_remove ( struct pci_device *pdev )
{
struct net_device *netdev = pci_get_drvdata ( pdev );
struct igbvf_adapter *adapter = netdev_priv ( netdev );
DBG ( "igbvf_remove\n" );
if ( adapter->hw.flash_address )
iounmap ( adapter->hw.flash_address );
if ( adapter->hw.hw_addr )
iounmap ( adapter->hw.hw_addr );
unregister_netdev ( netdev );
igbvf_reset ( adapter );
netdev_nullify ( netdev );
netdev_put ( netdev );
}
static struct pci_device_id igbvf_pci_tbl[] = {
PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0)
};
struct pci_driver igbvf_driver __pci_driver = {
.ids = igbvf_pci_tbl,
.id_count = (sizeof(igbvf_pci_tbl) / sizeof(igbvf_pci_tbl[0])),
.probe = igbvf_probe,
.remove = igbvf_remove,
};
+404
View File
@@ -0,0 +1,404 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#include "igbvf_mbx.h"
/**
* igbvf_poll_for_msg - Wait for message notification
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to write
*
* returns SUCCESS if it successfully received a message notification
**/
static s32 igbvf_poll_for_msg(struct e1000_hw *hw, u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
int countdown = mbx->timeout;
DEBUGFUNC("igbvf_poll_for_msg");
if (!countdown || !mbx->ops.check_for_msg)
goto out;
while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
countdown--;
if (!countdown)
break;
usec_delay(mbx->usec_delay);
}
/* if we failed, all future posted messages fail until reset */
if (!countdown)
mbx->timeout = 0;
out:
return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
}
/**
* igbvf_poll_for_ack - Wait for message acknowledgement
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to write
*
* returns SUCCESS if it successfully received a message acknowledgement
**/
static s32 igbvf_poll_for_ack(struct e1000_hw *hw, u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
int countdown = mbx->timeout;
DEBUGFUNC("igbvf_poll_for_ack");
if (!countdown || !mbx->ops.check_for_ack)
goto out;
while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
countdown--;
if (!countdown)
break;
usec_delay(mbx->usec_delay);
}
/* if we failed, all future posted messages fail until reset */
if (!countdown)
mbx->timeout = 0;
out:
return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
}
/**
* igbvf_read_posted_mbx - Wait for message notification and receive message
* @hw: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @mbx_id: id of mailbox to write
*
* returns SUCCESS if it successfully received a message notification and
* copied it into the receive buffer.
**/
static s32 igbvf_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_read_posted_mbx");
if (!mbx->ops.read)
goto out;
ret_val = igbvf_poll_for_msg(hw, mbx_id);
/* if ack received read message, otherwise we timed out */
if (!ret_val)
ret_val = mbx->ops.read(hw, msg, size, mbx_id);
out:
return ret_val;
}
/**
* igbvf_write_posted_mbx - Write a message to the mailbox, wait for ack
* @hw: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @mbx_id: id of mailbox to write
*
* returns SUCCESS if it successfully copied message into the buffer and
* received an ack to that message within delay * timeout period
**/
static s32 igbvf_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_write_posted_mbx");
/* exit if either we can't write or there isn't a defined timeout */
if (!mbx->ops.write || !mbx->timeout)
goto out;
/* send msg */
ret_val = mbx->ops.write(hw, msg, size, mbx_id);
/* if msg sent wait until we receive an ack */
if (!ret_val)
ret_val = igbvf_poll_for_ack(hw, mbx_id);
out:
return ret_val;
}
/**
* igbvf_init_mbx_ops_generic - Initialize NVM function pointers
* @hw: pointer to the HW structure
*
* Setups up the function pointers to no-op functions
**/
void igbvf_init_mbx_ops_generic(struct e1000_hw *hw)
{
struct e1000_mbx_info *mbx = &hw->mbx;
mbx->ops.read_posted = igbvf_read_posted_mbx;
mbx->ops.write_posted = igbvf_write_posted_mbx;
}
/**
* igbvf_read_v2p_mailbox - read v2p mailbox
* @hw: pointer to the HW structure
*
* This function is used to read the v2p mailbox without losing the read to
* clear status bits.
**/
static u32 igbvf_read_v2p_mailbox(struct e1000_hw *hw)
{
u32 v2p_mailbox = E1000_READ_REG(hw, E1000_V2PMAILBOX(0));
v2p_mailbox |= hw->dev_spec.vf.v2p_mailbox;
hw->dev_spec.vf.v2p_mailbox |= v2p_mailbox & E1000_V2PMAILBOX_R2C_BITS;
return v2p_mailbox;
}
/**
* igbvf_check_for_bit_vf - Determine if a status bit was set
* @hw: pointer to the HW structure
* @mask: bitmask for bits to be tested and cleared
*
* This function is used to check for the read to clear bits within
* the V2P mailbox.
**/
static s32 igbvf_check_for_bit_vf(struct e1000_hw *hw, u32 mask)
{
u32 v2p_mailbox = igbvf_read_v2p_mailbox(hw);
s32 ret_val = -E1000_ERR_MBX;
if (v2p_mailbox & mask)
ret_val = E1000_SUCCESS;
hw->dev_spec.vf.v2p_mailbox &= ~mask;
return ret_val;
}
/**
* igbvf_check_for_msg_vf - checks to see if the PF has sent mail
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to check
*
* returns SUCCESS if the PF has set the Status bit or else ERR_MBX
**/
static s32 igbvf_check_for_msg_vf(struct e1000_hw *hw, u16 mbx_id __unused)
{
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_check_for_msg_vf");
if (!igbvf_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFSTS)) {
ret_val = E1000_SUCCESS;
hw->mbx.stats.reqs++;
}
return ret_val;
}
/**
* igbvf_check_for_ack_vf - checks to see if the PF has ACK'd
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to check
*
* returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
**/
static s32 igbvf_check_for_ack_vf(struct e1000_hw *hw, u16 mbx_id __unused)
{
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_check_for_ack_vf");
if (!igbvf_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFACK)) {
ret_val = E1000_SUCCESS;
hw->mbx.stats.acks++;
}
return ret_val;
}
/**
* igbvf_check_for_rst_vf - checks to see if the PF has reset
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to check
*
* returns true if the PF has set the reset done bit or else false
**/
static s32 igbvf_check_for_rst_vf(struct e1000_hw *hw, u16 mbx_id __unused)
{
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_check_for_rst_vf");
if (!igbvf_check_for_bit_vf(hw, (E1000_V2PMAILBOX_RSTD |
E1000_V2PMAILBOX_RSTI))) {
ret_val = E1000_SUCCESS;
hw->mbx.stats.rsts++;
}
return ret_val;
}
/**
* igbvf_obtain_mbx_lock_vf - obtain mailbox lock
* @hw: pointer to the HW structure
*
* return SUCCESS if we obtained the mailbox lock
**/
static s32 igbvf_obtain_mbx_lock_vf(struct e1000_hw *hw)
{
s32 ret_val = -E1000_ERR_MBX;
DEBUGFUNC("igbvf_obtain_mbx_lock_vf");
/* Take ownership of the buffer */
E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
/* reserve mailbox for vf use */
if (igbvf_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU)
ret_val = E1000_SUCCESS;
return ret_val;
}
/**
* igbvf_write_mbx_vf - Write a message to the mailbox
* @hw: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @mbx_id: id of mailbox to write
*
* returns SUCCESS if it successfully copied message into the buffer
**/
static s32 igbvf_write_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size,
u16 mbx_id __unused)
{
s32 ret_val;
u16 i;
DEBUGFUNC("igbvf_write_mbx_vf");
/* lock the mailbox to prevent pf/vf race condition */
ret_val = igbvf_obtain_mbx_lock_vf(hw);
if (ret_val)
goto out_no_write;
/* flush msg and acks as we are overwriting the message buffer */
igbvf_check_for_msg_vf(hw, 0);
igbvf_check_for_ack_vf(hw, 0);
/* copy the caller specified message to the mailbox memory buffer */
for (i = 0; i < size; i++)
E1000_WRITE_REG_ARRAY(hw, E1000_VMBMEM(0), i, msg[i]);
/* update stats */
hw->mbx.stats.msgs_tx++;
/* Drop VFU and interrupt the PF to tell it a message has been sent */
E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_REQ);
out_no_write:
return ret_val;
}
/**
* igbvf_read_mbx_vf - Reads a message from the inbox intended for vf
* @hw: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @mbx_id: id of mailbox to read
*
* returns SUCCESS if it successfuly read message from buffer
**/
static s32 igbvf_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size,
u16 mbx_id __unused)
{
s32 ret_val = E1000_SUCCESS;
u16 i;
DEBUGFUNC("igbvf_read_mbx_vf");
/* lock the mailbox to prevent pf/vf race condition */
ret_val = igbvf_obtain_mbx_lock_vf(hw);
if (ret_val)
goto out_no_read;
/* copy the message from the mailbox memory buffer */
for (i = 0; i < size; i++)
msg[i] = E1000_READ_REG_ARRAY(hw, E1000_VMBMEM(0), i);
/* Acknowledge receipt and release mailbox, then we're done */
E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_ACK);
/* update stats */
hw->mbx.stats.msgs_rx++;
out_no_read:
return ret_val;
}
/**
* igbvf_init_mbx_params_vf - set initial values for vf mailbox
* @hw: pointer to the HW structure
*
* Initializes the hw->mbx struct to correct values for vf mailbox
*/
s32 igbvf_init_mbx_params_vf(struct e1000_hw *hw)
{
struct e1000_mbx_info *mbx = &hw->mbx;
/* start mailbox as timed out and let the reset_hw call set the timeout
* value to begin communications */
mbx->timeout = 0;
mbx->usec_delay = E1000_VF_MBX_INIT_DELAY;
mbx->size = E1000_VFMAILBOX_SIZE;
mbx->ops.read = igbvf_read_mbx_vf;
mbx->ops.write = igbvf_write_mbx_vf;
mbx->ops.read_posted = igbvf_read_posted_mbx;
mbx->ops.write_posted = igbvf_write_posted_mbx;
mbx->ops.check_for_msg = igbvf_check_for_msg_vf;
mbx->ops.check_for_ack = igbvf_check_for_ack_vf;
mbx->ops.check_for_rst = igbvf_check_for_rst_vf;
mbx->stats.msgs_tx = 0;
mbx->stats.msgs_rx = 0;
mbx->stats.reqs = 0;
mbx->stats.acks = 0;
mbx->stats.rsts = 0;
return E1000_SUCCESS;
}
+87
View File
@@ -0,0 +1,87 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#ifndef _IGBVF_MBX_H_
#define _IGBVF_MBX_H_
#include "igbvf_vf.h"
/* Define mailbox specific registers */
#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n)))
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
/* Define mailbox register bits */
#define E1000_V2PMAILBOX_REQ 0x00000001 /* Request for PF Ready bit */
#define E1000_V2PMAILBOX_ACK 0x00000002 /* Ack PF message received */
#define E1000_V2PMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
#define E1000_V2PMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
#define E1000_V2PMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */
#define E1000_V2PMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */
#define E1000_V2PMAILBOX_RSTI 0x00000040 /* PF has reset indication */
#define E1000_V2PMAILBOX_RSTD 0x00000080 /* PF has indicated reset done */
#define E1000_V2PMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
#define E1000_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
* PF. The reverse is true if it is E1000_PF_*.
* Message ACK's are the value or'd with 0xF0000000
*/
#define E1000_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with
* this are the ACK */
#define E1000_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with
* this are the NACK */
#define E1000_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still
clear to send requests */
#define E1000_VT_MSGINFO_SHIFT 16
/* bits 23:16 are used for exra info for certain messages */
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_RESET 0x01 /* VF requests reset */
#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
#define E1000_VF_SET_MULTICAST_COUNT_MASK (0x1F << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_MULTICAST_OVERFLOW (0x80 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_VLAN 0x04 /* VF requests to set VLAN */
#define E1000_VF_SET_VLAN_ADD (0x01 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_LPE 0x05 /* VF requests to set VMOLR.LPE */
#define E1000_VF_SET_PROMISC 0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
#define E1000_VF_SET_PROMISC_UNICAST (0x01 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
#define E1000_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
void igbvf_init_mbx_ops_generic(struct e1000_hw *hw);
s32 igbvf_init_mbx_params_vf(struct e1000_hw *);
#endif /* _IGBVF_MBX_H_ */
+121
View File
@@ -0,0 +1,121 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
/* glue for the OS-dependent part of igbvf
* includes register access macros
*/
#ifndef _IGBVF_OSDEP_H_
#define _IGBVF_OSDEP_H_
#define u8 unsigned char
#define bool boolean_t
#define dma_addr_t unsigned long
#define __le16 uint16_t
#define __le32 uint32_t
#define __le64 uint64_t
#define __iomem
#define __devinit
#define ____cacheline_aligned_in_smp
#define msleep(x) mdelay(x)
#define ETH_FCS_LEN 4
typedef int spinlock_t;
typedef enum {
false = 0,
true = 1
} boolean_t;
#define TRUE 1
#define FALSE 0
#define usec_delay(x) udelay(x)
#define msec_delay(x) mdelay(x)
#define msec_delay_irq(x) mdelay(x)
#define PCI_COMMAND_REGISTER PCI_COMMAND
#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
#define ETH_ADDR_LEN ETH_ALEN
#define DEBUGOUT(S) if (0) { printf(S); }
#define DEBUGOUT1(S, A...) if (0) { printf(S, A); }
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
#define E1000_WRITE_REG(a, reg, value) do { \
writel((value), ((a)->hw_addr + reg)); } while (0)
#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) do { \
writel((value), ((a)->hw_addr + reg + ((offset) << 2))); } while (0)
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + reg + ((offset) << 2)))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
writew((value), ((a)->hw_addr + reg + ((offset) << 1))))
#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
readw((a)->hw_addr + reg + ((offset) << 1)))
#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
writeb((value), ((a)->hw_addr + reg + (offset))))
#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
readb((a)->hw_addr + reg + (offset)))
#define E1000_WRITE_REG_IO(a, reg, offset) do { \
outl(reg, ((a)->io_base)); \
outl(offset, ((a)->io_base + 4)); } while(0)
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
writel((value), ((a)->flash_address + reg)))
#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
writew((value), ((a)->flash_address + reg)))
#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
#endif /* _IGBVF_OSDEP_H_ */
+338
View File
@@ -0,0 +1,338 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#ifndef _IGBVF_REGS_H_
#define _IGBVF_REGS_H_
#define E1000_CTRL 0x00000 /* Device Control - RW */
#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
#define E1000_STATUS 0x00008 /* Device Status - RO */
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FEXT 0x0002C /* Future Extended - RW */
#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
#define E1000_RCTL 0x00100 /* Rx Control - RW */
#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */
#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */
#define E1000_TCTL 0x00400 /* Tx Control - RW */
#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */
#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */
#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_PBS 0x01008 /* Packet Buffer Size */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
#define E1000_FLSWCTL 0x01030 /* FLASH control register */
#define E1000_FLSWDATA 0x01034 /* FLASH data register */
#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */
#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */
#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */
#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n)))
#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */
#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
/* Split and Replication Rx Control - RW */
#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */
#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */
#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */
#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */
#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */
#define E1000_RXCTL(_n) (0x0C014 + (0x40 * (_n)))
#define E1000_RQDPC(_n) (0x0C030 + (0x40 * (_n)))
#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
/*
* Convenience macros
*
* Note: "_n" is the queue number of the register to be written to.
*
* Example usage:
* E1000_RDBAL_REG(current_rx_queue)
*/
#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
(0x0C000 + ((_n) * 0x40)))
#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
(0x0C004 + ((_n) * 0x40)))
#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
(0x0C008 + ((_n) * 0x40)))
#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
(0x0C00C + ((_n) * 0x40)))
#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
(0x0C010 + ((_n) * 0x40)))
#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
(0x0C018 + ((_n) * 0x40)))
#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
(0x0C028 + ((_n) * 0x40)))
#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
(0x0E000 + ((_n) * 0x40)))
#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
(0x0E004 + ((_n) * 0x40)))
#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
(0x0E008 + ((_n) * 0x40)))
#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
(0x0E010 + ((_n) * 0x40)))
#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
(0x0E018 + ((_n) * 0x40)))
#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
(0x0E028 + ((_n) * 0x40)))
#define E1000_TARC(_n) (0x03840 + (_n << 8))
#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
(0x0E038 + ((_n) * 0x40)))
#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
(0x0E03C + ((_n) * 0x40)))
#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */
#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */
#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
(0x054E0 + ((_i - 16) * 8)))
#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
(0x054E4 + ((_i - 16) * 8)))
#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8))
#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8))
#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8))
#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */
#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */
#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */
#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */
#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */
#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */
#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */
#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */
#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
#define E1000_COLC 0x04028 /* Collision Count - R/clr */
#define E1000_DC 0x04030 /* Defer Count - R/clr */
#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */
#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */
#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */
#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */
#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */
#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */
#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */
#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */
#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */
#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */
#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */
#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */
#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */
#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */
#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */
#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */
#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */
#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */
#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
#define E1000_VFGPRC 0x00F10
#define E1000_VFGORC 0x00F18
#define E1000_VFMPRC 0x00F3C
#define E1000_VFGPTC 0x00F14
#define E1000_VFGOTC 0x00F34
#define E1000_VFGOTLBC 0x00F50
#define E1000_VFGPTLBC 0x00F44
#define E1000_VFGORLBC 0x00F48
#define E1000_VFGPRLBC 0x00F40
#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */
#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */
#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */
#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */
#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */
#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */
#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */
#define E1000_RPTHC 0x04104 /* Rx Packets To Host */
#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */
#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */
#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */
#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */
#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
#define E1000_LENERRS 0x04138 /* Length Errors Count */
#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */
#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */
#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */
#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */
#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */
#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */
#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */
#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */
#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */
#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */
#define E1000_WUC 0x05800 /* Wakeup Control - RW */
#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
#define E1000_WUS 0x05810 /* Wakeup Status - RO */
#define E1000_MANC 0x05820 /* Management Control - RW */
#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */
#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
#define E1000_HOST_IF 0x08800 /* Host Interface */
#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
#define E1000_MDPHYA 0x0003C /* PHY address - RW */
#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
#define E1000_GCR 0x05B00 /* PCI-Ex Control */
#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */
#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
#define E1000_SWSM 0x05B50 /* SW Semaphore */
#define E1000_FWSM 0x05B54 /* FW Semaphore */
#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */
#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */
#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
#define E1000_HICR 0x08F00 /* Host Interface Control */
/* RSS registers */
#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/
#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
* (_i) - RW */
#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
* low reg - RW */
#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
* upper reg - RW */
#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
* message reg - RW */
#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
* vector ctrl reg - RW */
#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */
#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
#endif /* _IGBVF_REGS_H_ */
+455
View File
@@ -0,0 +1,455 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#include "igbvf_vf.h"
static s32 igbvf_init_mac_params_vf(struct e1000_hw *hw);
static s32 igbvf_check_for_link_vf(struct e1000_hw *hw);
static s32 igbvf_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
static s32 igbvf_init_hw_vf(struct e1000_hw *hw);
static s32 igbvf_reset_hw_vf(struct e1000_hw *hw);
static void igbvf_update_mc_addr_list_vf(struct e1000_hw *hw, u8 *, u32);
static void igbvf_rar_set_vf(struct e1000_hw *, u8 *, u32);
static s32 igbvf_read_mac_addr_vf(struct e1000_hw *);
/**
* igbvf_init_mac_params_vf - Inits MAC params
* @hw: pointer to the HW structure
**/
static s32 igbvf_init_mac_params_vf(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
DEBUGFUNC("igbvf_init_mac_params_vf");
/* VF's have no MTA Registers - PF feature only */
mac->mta_reg_count = 128;
/* VF's have no access to RAR entries */
mac->rar_entry_count = 1;
/* Function pointers */
/* reset */
mac->ops.reset_hw = igbvf_reset_hw_vf;
/* hw initialization */
mac->ops.init_hw = igbvf_init_hw_vf;
/* check for link */
mac->ops.check_for_link = igbvf_check_for_link_vf;
/* link info */
mac->ops.get_link_up_info = igbvf_get_link_up_info_vf;
/* multicast address update */
mac->ops.update_mc_addr_list = igbvf_update_mc_addr_list_vf;
/* set mac address */
mac->ops.rar_set = igbvf_rar_set_vf;
/* read mac address */
mac->ops.read_mac_addr = igbvf_read_mac_addr_vf;
return E1000_SUCCESS;
}
/**
* igbvf_init_function_pointers_vf - Inits function pointers
* @hw: pointer to the HW structure
**/
void igbvf_init_function_pointers_vf(struct e1000_hw *hw)
{
DEBUGFUNC("igbvf_init_function_pointers_vf");
hw->mac.ops.init_params = igbvf_init_mac_params_vf;
hw->mbx.ops.init_params = igbvf_init_mbx_params_vf;
}
/**
* igbvf_get_link_up_info_vf - Gets link info.
* @hw: pointer to the HW structure
* @speed: pointer to 16 bit value to store link speed.
* @duplex: pointer to 16 bit value to store duplex.
*
* Since we cannot read the PHY and get accurate link info, we must rely upon
* the status register's data which is often stale and inaccurate.
**/
static s32 igbvf_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
u16 *duplex)
{
s32 status;
DEBUGFUNC("igbvf_get_link_up_info_vf");
status = E1000_READ_REG(hw, E1000_STATUS);
if (status & E1000_STATUS_SPEED_1000) {
*speed = SPEED_1000;
DEBUGOUT("1000 Mbs, ");
} else if (status & E1000_STATUS_SPEED_100) {
*speed = SPEED_100;
DEBUGOUT("100 Mbs, ");
} else {
*speed = SPEED_10;
DEBUGOUT("10 Mbs, ");
}
if (status & E1000_STATUS_FD) {
*duplex = FULL_DUPLEX;
DEBUGOUT("Full Duplex\n");
} else {
*duplex = HALF_DUPLEX;
DEBUGOUT("Half Duplex\n");
}
return E1000_SUCCESS;
}
/**
* igbvf_reset_hw_vf - Resets the HW
* @hw: pointer to the HW structure
*
* VF's provide a function level reset. This is done using bit 26 of ctrl_reg.
* This is all the reset we can perform on a VF.
**/
static s32 igbvf_reset_hw_vf(struct e1000_hw *hw)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 timeout = E1000_VF_INIT_TIMEOUT;
s32 ret_val = -E1000_ERR_MAC_INIT;
u32 ctrl, msgbuf[3];
u8 *addr = (u8 *)(&msgbuf[1]);
DEBUGFUNC("igbvf_reset_hw_vf");
DEBUGOUT("Issuing a function level reset to MAC\n");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
/* we cannot reset while the RSTI / RSTD bits are asserted */
while (!mbx->ops.check_for_rst(hw, 0) && timeout) {
timeout--;
usec_delay(5);
}
if (timeout) {
/* mailbox timeout can now become active */
mbx->timeout = E1000_VF_MBX_INIT_TIMEOUT;
msgbuf[0] = E1000_VF_RESET;
mbx->ops.write_posted(hw, msgbuf, 1, 0);
msec_delay(10);
/* set our "perm_addr" based on info provided by PF */
ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
if (!ret_val) {
if (msgbuf[0] == (E1000_VF_RESET |
E1000_VT_MSGTYPE_ACK))
memcpy(hw->mac.perm_addr, addr, 6);
else
ret_val = -E1000_ERR_MAC_INIT;
}
}
return ret_val;
}
/**
* igbvf_init_hw_vf - Inits the HW
* @hw: pointer to the HW structure
*
* Not much to do here except clear the PF Reset indication if there is one.
**/
static s32 igbvf_init_hw_vf(struct e1000_hw *hw)
{
DEBUGFUNC("igbvf_init_hw_vf");
/* attempt to set and restore our mac address */
igbvf_rar_set_vf(hw, hw->mac.addr, 0);
return E1000_SUCCESS;
}
/**
* igbvf_rar_set_vf - set device MAC address
* @hw: pointer to the HW structure
* @addr: pointer to the receive address
* @index receive address array register
**/
static void igbvf_rar_set_vf(struct e1000_hw *hw, u8 * addr, u32 index __unused)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf[3];
u8 *msg_addr = (u8 *)(&msgbuf[1]);
s32 ret_val;
memset(msgbuf, 0, 12);
msgbuf[0] = E1000_VF_SET_MAC_ADDR;
memcpy(msg_addr, addr, 6);
ret_val = mbx->ops.write_posted(hw, msgbuf, 3, 0);
if (!ret_val)
ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS;
/* if nacked the address was rejected, use "perm_addr" */
if (!ret_val &&
(msgbuf[0] == (E1000_VF_SET_MAC_ADDR | E1000_VT_MSGTYPE_NACK)))
igbvf_read_mac_addr_vf(hw);
}
/**
* igbvf_hash_mc_addr_vf - Generate a multicast hash value
* @hw: pointer to the HW structure
* @mc_addr: pointer to a multicast address
*
* Generates a multicast address hash value which is used to determine
* the multicast filter table array address and new table value. See
* igbvf_mta_set_generic()
**/
static u32 igbvf_hash_mc_addr_vf(struct e1000_hw *hw, u8 *mc_addr)
{
u32 hash_value, hash_mask;
u8 bit_shift = 0;
DEBUGFUNC("igbvf_hash_mc_addr_generic");
/* Register count multiplied by bits per register */
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
/*
* The bit_shift is the number of left-shifts
* where 0xFF would still fall within the hash mask.
*/
while (hash_mask >> bit_shift != 0xFF)
bit_shift++;
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
(((u16) mc_addr[5]) << bit_shift)));
return hash_value;
}
/**
* igbvf_update_mc_addr_list_vf - Update Multicast addresses
* @hw: pointer to the HW structure
* @mc_addr_list: array of multicast addresses to program
* @mc_addr_count: number of multicast addresses to program
*
* Updates the Multicast Table Array.
* The caller must have a packed mc_addr_list of multicast addresses.
**/
void igbvf_update_mc_addr_list_vf(struct e1000_hw *hw,
u8 *mc_addr_list, u32 mc_addr_count)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf[E1000_VFMAILBOX_SIZE];
u16 *hash_list = (u16 *)&msgbuf[1];
u32 hash_value;
u32 i;
DEBUGFUNC("igbvf_update_mc_addr_list_vf");
/* Each entry in the list uses 1 16 bit word. We have 30
* 16 bit words available in our HW msg buffer (minus 1 for the
* msg type). That's 30 hash values if we pack 'em right. If
* there are more than 30 MC addresses to add then punt the
* extras for now and then add code to handle more than 30 later.
* It would be unusual for a server to request that many multi-cast
* addresses except for in large enterprise network environments.
*/
DEBUGOUT1("MC Addr Count = %d\n", mc_addr_count);
msgbuf[0] = E1000_VF_SET_MULTICAST;
if (mc_addr_count > 30) {
msgbuf[0] |= E1000_VF_SET_MULTICAST_OVERFLOW;
mc_addr_count = 30;
}
msgbuf[0] |= mc_addr_count << E1000_VT_MSGINFO_SHIFT;
for (i = 0; i < mc_addr_count; i++) {
hash_value = igbvf_hash_mc_addr_vf(hw, mc_addr_list);
DEBUGOUT1("Hash value = 0x%03X\n", hash_value);
hash_list[i] = hash_value & 0x0FFF;
mc_addr_list += ETH_ADDR_LEN;
}
mbx->ops.write_posted(hw, msgbuf, E1000_VFMAILBOX_SIZE, 0);
}
/**
* igbvf_vfta_set_vf - Set/Unset vlan filter table address
* @hw: pointer to the HW structure
* @vid: determines the vfta register and bit to set/unset
* @set: if true then set bit, else clear bit
**/
void igbvf_vfta_set_vf(struct e1000_hw *hw, u16 vid, bool set)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf[2];
msgbuf[0] = E1000_VF_SET_VLAN;
msgbuf[1] = vid;
/* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
if (set)
msgbuf[0] |= E1000_VF_SET_VLAN_ADD;
mbx->ops.write_posted(hw, msgbuf, 2, 0);
}
/** igbvf_rlpml_set_vf - Set the maximum receive packet length
* @hw: pointer to the HW structure
* @max_size: value to assign to max frame size
**/
void igbvf_rlpml_set_vf(struct e1000_hw *hw, u16 max_size)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf[2];
msgbuf[0] = E1000_VF_SET_LPE;
msgbuf[1] = max_size;
mbx->ops.write_posted(hw, msgbuf, 2, 0);
}
/**
* igbvf_promisc_set_vf - Set flags for Unicast or Multicast promisc
* @hw: pointer to the HW structure
* @uni: boolean indicating unicast promisc status
* @multi: boolean indicating multicast promisc status
**/
s32 igbvf_promisc_set_vf(struct e1000_hw *hw, enum e1000_promisc_type type)
{
struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf = E1000_VF_SET_PROMISC;
s32 ret_val;
switch (type) {
case e1000_promisc_multicast:
msgbuf |= E1000_VF_SET_PROMISC_MULTICAST;
break;
case e1000_promisc_enabled:
msgbuf |= E1000_VF_SET_PROMISC_MULTICAST;
case e1000_promisc_unicast:
msgbuf |= E1000_VF_SET_PROMISC_UNICAST;
case e1000_promisc_disabled:
break;
default:
return -E1000_ERR_MAC_INIT;
}
ret_val = mbx->ops.write_posted(hw, &msgbuf, 1, 0);
if (!ret_val)
ret_val = mbx->ops.read_posted(hw, &msgbuf, 1, 0);
if (!ret_val && !(msgbuf & E1000_VT_MSGTYPE_ACK))
ret_val = -E1000_ERR_MAC_INIT;
return ret_val;
}
/**
* igbvf_read_mac_addr_vf - Read device MAC address
* @hw: pointer to the HW structure
**/
static s32 igbvf_read_mac_addr_vf(struct e1000_hw *hw)
{
int i;
for (i = 0; i < ETH_ADDR_LEN; i++)
hw->mac.addr[i] = hw->mac.perm_addr[i];
return E1000_SUCCESS;
}
/**
* igbvf_check_for_link_vf - Check for link for a virtual interface
* @hw: pointer to the HW structure
*
* Checks to see if the underlying PF is still talking to the VF and
* if it is then it reports the link state to the hardware, otherwise
* it reports link down and returns an error.
**/
static s32 igbvf_check_for_link_vf(struct e1000_hw *hw)
{
struct e1000_mbx_info *mbx = &hw->mbx;
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val = E1000_SUCCESS;
u32 in_msg = 0;
DEBUGFUNC("igbvf_check_for_link_vf");
/*
* We only want to run this if there has been a rst asserted.
* in this case that could mean a link change, device reset,
* or a virtual function reset
*/
/* If we were hit with a reset drop the link */
if (!mbx->ops.check_for_rst(hw, 0))
mac->get_link_status = true;
if (!mac->get_link_status)
goto out;
/* if link status is down no point in checking to see if pf is up */
if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU))
goto out;
/* if the read failed it could just be a mailbox collision, best wait
* until we are called again and don't report an error */
if (mbx->ops.read(hw, &in_msg, 1, 0))
goto out;
/* if incoming message isn't clear to send we are waiting on response */
if (!(in_msg & E1000_VT_MSGTYPE_CTS)) {
/* message is not CTS and is NACK we have lost CTS status */
if (in_msg & E1000_VT_MSGTYPE_NACK)
ret_val = -E1000_ERR_MAC_INIT;
goto out;
}
/* at this point we know the PF is talking to us, check and see if
* we are still accepting timeout or if we had a timeout failure.
* if we failed then we will need to reinit */
if (!mbx->timeout) {
ret_val = -E1000_ERR_MAC_INIT;
goto out;
}
/* if we passed all the tests above then the link is up and we no
* longer need to check for link */
mac->get_link_status = false;
out:
return ret_val;
}
+345
View File
@@ -0,0 +1,345 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
Copyright(c) 1999 - 2008 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
FILE_LICENCE ( GPL2_ONLY );
#ifndef _IGBVF_VF_H_
#define _IGBVF_VF_H_
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <byteswap.h>
#include <errno.h>
#include <ipxe/pci.h>
#include <ipxe/malloc.h>
#include <ipxe/if_ether.h>
#include <ipxe/io.h>
#include <ipxe/ethernet.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include "igbvf_osdep.h"
#include "igbvf_regs.h"
#include "igbvf_defines.h"
struct e1000_hw;
#define E1000_DEV_ID_82576_VF 0x10CA
#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
/* Additional Descriptor Control definitions */
#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
/* SRRCTL bit definitions */
#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000
#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
#define E1000_SRRCTL_DROP_EN 0x80000000
#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
/* Interrupt Defines */
#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
#define E1000_EITR(_n) (0x01680 + ((_n) << 2))
#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
#define E1000_IVAR_VALID 0x80
/* Receive Descriptor - Advanced */
union e1000_adv_rx_desc {
struct {
u64 pkt_addr; /* Packet buffer address */
u64 hdr_addr; /* Header buffer address */
} read;
struct {
struct {
union {
u32 data;
struct {
u16 pkt_info; /* RSS type, Packet type */
u16 hdr_info; /* Split Header,
* header buffer length */
} hs_rss;
} lo_dword;
union {
u32 rss; /* RSS Hash */
struct {
u16 ip_id; /* IP id */
u16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
u32 status_error; /* ext status/error */
u16 length; /* Packet length */
u16 vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
/* Transmit Descriptor - Advanced */
union e1000_adv_tx_desc {
struct {
u64 buffer_addr; /* Address of descriptor's data buf */
u32 cmd_type_len;
u32 olinfo_status;
} read;
struct {
u64 rsvd; /* Reserved */
u32 nxtseq_seed;
u32 status;
} wb;
};
/* Adv Transmit Descriptor Config Masks */
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
/* Context descriptors */
struct e1000_adv_tx_context_desc {
u32 vlan_macip_lens;
u32 seqnum_seed;
u32 type_tucmd_mlhl;
u32 mss_l4len_idx;
};
#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
enum e1000_mac_type {
e1000_undefined = 0,
e1000_vfadapt,
e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
};
struct e1000_vf_stats {
u64 base_gprc;
u64 base_gptc;
u64 base_gorc;
u64 base_gotc;
u64 base_mprc;
u64 base_gotlbc;
u64 base_gptlbc;
u64 base_gorlbc;
u64 base_gprlbc;
u32 last_gprc;
u32 last_gptc;
u32 last_gorc;
u32 last_gotc;
u32 last_mprc;
u32 last_gotlbc;
u32 last_gptlbc;
u32 last_gorlbc;
u32 last_gprlbc;
u64 gprc;
u64 gptc;
u64 gorc;
u64 gotc;
u64 mprc;
u64 gotlbc;
u64 gptlbc;
u64 gorlbc;
u64 gprlbc;
};
#include "igbvf_mbx.h"
struct e1000_mac_operations {
/* Function pointers for the MAC. */
s32 (*init_params)(struct e1000_hw *);
s32 (*check_for_link)(struct e1000_hw *);
void (*clear_vfta)(struct e1000_hw *);
s32 (*get_bus_info)(struct e1000_hw *);
s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
s32 (*reset_hw)(struct e1000_hw *);
s32 (*init_hw)(struct e1000_hw *);
s32 (*setup_link)(struct e1000_hw *);
void (*write_vfta)(struct e1000_hw *, u32, u32);
void (*mta_set)(struct e1000_hw *, u32);
void (*rar_set)(struct e1000_hw *, u8*, u32);
s32 (*read_mac_addr)(struct e1000_hw *);
};
struct e1000_mac_info {
struct e1000_mac_operations ops;
u8 addr[6];
u8 perm_addr[6];
enum e1000_mac_type type;
u16 mta_reg_count;
u16 rar_entry_count;
bool get_link_status;
};
enum e1000_bus_type {
e1000_bus_type_unknown = 0,
e1000_bus_type_pci,
e1000_bus_type_pcix,
e1000_bus_type_pci_express,
e1000_bus_type_reserved
};
enum e1000_bus_speed {
e1000_bus_speed_unknown = 0,
e1000_bus_speed_33,
e1000_bus_speed_66,
e1000_bus_speed_100,
e1000_bus_speed_120,
e1000_bus_speed_133,
e1000_bus_speed_2500,
e1000_bus_speed_5000,
e1000_bus_speed_reserved
};
enum e1000_bus_width {
e1000_bus_width_unknown = 0,
e1000_bus_width_pcie_x1,
e1000_bus_width_pcie_x2,
e1000_bus_width_pcie_x4 = 4,
e1000_bus_width_pcie_x8 = 8,
e1000_bus_width_32,
e1000_bus_width_64,
e1000_bus_width_reserved
};
struct e1000_bus_info {
enum e1000_bus_type type;
enum e1000_bus_speed speed;
enum e1000_bus_width width;
u16 func;
u16 pci_cmd_word;
};
struct e1000_mbx_operations {
s32 (*init_params)(struct e1000_hw *hw);
s32 (*read)(struct e1000_hw *, u32 *, u16, u16);
s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*check_for_msg)(struct e1000_hw *, u16);
s32 (*check_for_ack)(struct e1000_hw *, u16);
s32 (*check_for_rst)(struct e1000_hw *, u16);
};
struct e1000_mbx_stats {
u32 msgs_tx;
u32 msgs_rx;
u32 acks;
u32 reqs;
u32 rsts;
};
struct e1000_mbx_info {
struct e1000_mbx_operations ops;
struct e1000_mbx_stats stats;
u32 timeout;
u32 usec_delay;
u16 size;
};
struct e1000_dev_spec_vf {
u32 vf_number;
u32 v2p_mailbox;
};
struct e1000_hw {
void *back;
u8 __iomem *hw_addr;
u8 __iomem *flash_address;
unsigned long io_base;
struct e1000_mac_info mac;
struct e1000_bus_info bus;
struct e1000_mbx_info mbx;
union {
struct e1000_dev_spec_vf vf;
} dev_spec;
u16 device_id;
u16 subsystem_vendor_id;
u16 subsystem_device_id;
u16 vendor_id;
u8 revision_id;
};
enum e1000_promisc_type {
e1000_promisc_disabled = 0, /* all promisc modes disabled */
e1000_promisc_unicast = 1, /* unicast promiscuous enabled */
e1000_promisc_multicast = 2, /* multicast promiscuous enabled */
e1000_promisc_enabled = 3, /* both uni and multicast promisc */
e1000_num_promisc_types
};
/* These functions must be implemented by drivers */
s32 igbvf_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
void igbvf_vfta_set_vf(struct e1000_hw *, u16, bool);
void igbvf_rlpml_set_vf(struct e1000_hw *, u16);
s32 igbvf_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type);
#endif /* _IGBVF_VF_H_ */
+2 -2
View File
@@ -2061,7 +2061,7 @@ static int phantom_probe ( struct pci_device *pci,
assert ( phantom->port < PHN_MAX_NUM_PORTS );
settings_init ( &phantom->settings,
&phantom_settings_operations,
&netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC );
&netdev->refcnt, PHN_CLP_TAG_MAGIC );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -2111,7 +2111,7 @@ static int phantom_probe ( struct pci_device *pci,
/* Register settings blocks */
parent_settings = netdev_settings ( netdev );
if ( ( rc = register_settings ( &phantom->settings,
parent_settings ) ) != 0 ) {
parent_settings, "clp" ) ) != 0 ) {
DBGC ( phantom, "Phantom %p could not register settings: "
"%s\n", phantom, strerror ( rc ) );
goto err_register_settings;
+1 -1
View File
@@ -1832,7 +1832,7 @@ static void rtl8169_irq_disable ( struct rtl8169_private *tp )
DBGP ( "rtl8169_irq_disable\n" );
rtl8169_irq_mask_and_ack ( ioaddr );
RTL_W16 ( IntrMask, 0x0000 );
}
/*** iPXE Core API Routines ***/
+2
View File
@@ -38,6 +38,8 @@
* Indent Options: indent -kr -i8
*************************************************************************/
FILE_LICENCE ( GPL2_OR_LATER );
#include "etherboot.h"
#include "nic.h"
#include <ipxe/pci.h>
+2
View File
@@ -24,6 +24,8 @@
* Copyright (c) 2006 by Timothy Legge <tlegge@rogers.com>
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifndef VELOCITY_H
#define VELOCITY_H
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <ipxe/nvs.h>
#include <ipxe/pci.h>
#include <ipxe/pcivpd.h>
#include <ipxe/nvsvpd.h>
/** @file
*
* Non-Volatile Storage using Vital Product Data
*
*/
/**
* Read from VPD
*
* @v nvs NVS device
* @v address Starting address
* @v buf Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int address,
void *data, size_t len ) {
struct nvs_vpd_device *nvsvpd =
container_of ( nvs, struct nvs_vpd_device, nvs );
int rc;
if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, ( nvsvpd->address + address ),
data, len ) ) != 0 ) {
DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not read "
"[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
address, ( address + len ), strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Write to VPD
*
* @v nvs NVS device
* @v address Starting address
* @v buf Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
const void *data, size_t len ) {
struct nvs_vpd_device *nvsvpd =
container_of ( nvs, struct nvs_vpd_device, nvs );
int rc;
if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, ( nvsvpd->address + address ),
data, len ) ) != 0 ) {
DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not write "
"[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
address, ( address + len ), strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Initialise NVS VPD device
*
* @v nvsvpd NVS VPD device
* @v pci PCI device
* @ret rc Return status code
*/
int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
unsigned int field ) {
size_t len;
int rc;
/* Initialise VPD device */
if ( ( rc = pci_vpd_init ( &nvsvpd->vpd, pci ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS could not initialise "
"VPD: %s\n", PCI_ARGS ( pci ), strerror ( rc ) );
return rc;
}
/* Locate VPD field */
if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &nvsvpd->address,
&len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS could not locate VPD field "
PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
return rc;
}
/* Initialise NVS device */
nvsvpd->nvs.block_size = 1;
nvsvpd->nvs.size = len;
nvsvpd->nvs.read = nvs_vpd_read;
nvsvpd->nvs.write = nvs_vpd_write;
DBGC ( pci, PCI_FMT " NVS using VPD field " PCI_VPD_FIELD_FMT " at "
"[%04x,%04x)\n", PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
nvsvpd->address, ( nvsvpd->address + nvsvpd->nvs.size ) );
return 0;
}
+47 -17
View File
@@ -1,27 +1,57 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/netdevice.h>
#include <hci/ifmgmt_cmd.h>
#include <usr/autoboot.h>
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Booting commands
*
*/
/** "autoboot" command descriptor */
static struct command_descriptor autoboot_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]", "Attempt to boot the system" );
/**
* "autoboot" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int autoboot_exec ( int argc, char **argv ) {
if ( argc != 1 ) {
printf ( "Usage:\n"
" %s\n"
"\n"
"Attempts to boot the system\n",
argv[0] );
return 1;
}
autoboot();
/* Can never return success by definition */
return 1;
return ifcommon_exec ( argc, argv, &autoboot_cmd, netboot, 0 );
}
struct command autoboot_command __command = {
.name = "autoboot",
.exec = autoboot_exec,
/** Booting commands */
struct command autoboot_commands[] __command = {
{
.name = "autoboot",
.exec = autoboot_exec,
},
};
+84 -19
View File
@@ -1,38 +1,103 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/settings.h>
#include <ipxe/settings_ui.h>
FILE_LICENCE ( GPL2_OR_LATER );
static int config_exec ( int argc, char **argv ) {
char *settings_name;
struct settings *settings;
int rc;
/** @file
*
* Configuration UI commands
*
*/
if ( argc > 2 ) {
printf ( "Usage: %s [scope]\n"
"Opens the option configuration console\n", argv[0] );
return 1;
}
/** "config" options */
struct config_options {};
settings_name = ( ( argc == 2 ) ? argv[1] : "" );
settings = find_settings ( settings_name );
if ( ! settings ) {
printf ( "No such scope \"%s\"\n", settings_name );
return 1;
}
/** "config" option list */
static struct option_descriptor config_opts[] = {};
if ( ( rc = settings_ui ( settings ) ) != 0 ) {
printf ( "Could not save settings: %s\n",
strerror ( rc ) );
return 1;
/** "config" command descriptor */
static struct command_descriptor config_cmd =
COMMAND_DESC ( struct config_options, config_opts, 0, 1,
"[<scope>]",
"Open the option configuration console" );
/**
* Parse settings scope name
*
* @v text Text
* @ret value Integer value
* @ret rc Return status code
*/
static int parse_settings ( const char *text, struct settings **value ) {
/* Sanity check */
assert ( text != NULL );
/* Parse scope name */
*value = find_settings ( text );
if ( ! *value ) {
printf ( "\"%s\": no such scope\n", text );
return -EINVAL;
}
return 0;
}
/**
* "config" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int config_exec ( int argc, char **argv ) {
struct config_options opts;
struct settings *settings;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &config_cmd, &opts ) ) != 0 )
return rc;
/* Parse settings option, if present */
if ( ( rc = parse_settings ( ( ( optind < argc ) ? argv[optind] : "" ),
&settings ) ) != 0 )
return rc;
/* Run settings UI */
if ( ( rc = settings_ui ( settings ) ) != 0 ) {
printf ( "Could not save settings: %s\n", strerror ( rc ) );
return rc;
}
return 0;
}
/** Configuration UI commands */
struct command config_command __command = {
.name = "config",
.exec = config_exec,
+35 -120
View File
@@ -30,7 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/netdevice.h>
#include <ipxe/in.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/dhcpmgmt.h>
#include <hci/ifmgmt_cmd.h>
/** @file
*
@@ -38,26 +40,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/**
* "dhcp" command syntax message
*
* @v argv Argument list
*/
static void dhcp_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s [<interface>] [<interface>...]\n"
"\n"
"Configure a network interface using DHCP\n",
argv[0] );
}
/** "dhcp" command descriptor */
static struct command_descriptor dhcp_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>] [<interface>...]",
"Configure network interface(s) using DHCP" );
/**
* Execute "dhcp" command for a network device
*
* @v netdev Network device
* @ret rc Exit code
* @ret rc Return status code
*/
static int dhcp_exec_netdev ( struct net_device *netdev ) {
static int dhcp_payload ( struct net_device *netdev ) {
int rc;
if ( ( rc = dhcp ( netdev ) ) != 0 ) {
@@ -67,145 +62,65 @@ static int dhcp_exec_netdev ( struct net_device *netdev ) {
/* Close device on failure, to avoid memory exhaustion */
netdev_close ( netdev );
return 1;
return rc;
}
return 0;
}
/**
* Execute "dhcp" command for a named network device
*
* @v netdev_name Network device name
* @ret rc Exit code
*/
static int dhcp_exec_name ( const char *netdev_name ) {
struct net_device *netdev;
netdev = find_netdev ( netdev_name );
if ( ! netdev ) {
printf ( "No such interface \"%s\"\n", netdev_name );
return 1;
}
return dhcp_exec_netdev ( netdev );
}
/**
* The "dhcp" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int dhcp_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *netdev_name;
struct net_device *netdev;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
dhcp_syntax ( argv );
return 1;
}
}
if ( optind != argc ) {
/* Treat arguments as a list of interfaces to try */
while ( optind != argc ) {
netdev_name = argv[optind++];
if ( ( rc = dhcp_exec_name ( netdev_name ) ) == 0 )
return 0;
}
} else {
/* Try all interfaces */
for_each_netdev ( netdev ) {
if ( ( rc = dhcp_exec_netdev ( netdev ) ) == 0 )
return 0;
}
}
return 1;
return ifcommon_exec ( argc, argv, &dhcp_cmd, dhcp_payload, 1 );
}
/**
* "pxebs" command syntax message
*
* @v argv Argument list
*/
static void pxebs_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <interface> <server_type>\n"
"\n"
"Perform PXE Boot Server discovery\n",
argv[0] );
}
/** "pxebs" options */
struct pxebs_options {};
/** "pxebs" option list */
static struct option_descriptor pxebs_opts[] = {};
/** "pxebs" command descriptor */
static struct command_descriptor pxebs_cmd =
COMMAND_DESC ( struct pxebs_options, pxebs_opts, 2, 2,
"<interface> <server_type>",
"Perform PXE Boot Server discovery" );
/**
* The "pxebs" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int pxebs_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *netdev_txt;
const char *pxe_type_txt;
struct pxebs_options opts;
struct net_device *netdev;
unsigned int pxe_type;
char *end;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
pxebs_syntax ( argv );
return 1;
}
}
if ( optind != ( argc - 2 ) ) {
pxebs_syntax ( argv );
return 1;
}
netdev_txt = argv[optind];
pxe_type_txt = argv[ optind + 1 ];
if ( ( rc = parse_options ( argc, argv, &pxebs_cmd, &opts ) ) != 0 )
return rc;
/* Parse arguments */
netdev = find_netdev ( netdev_txt );
if ( ! netdev ) {
printf ( "No such interface: %s\n", netdev_txt );
return 1;
}
pxe_type = strtoul ( pxe_type_txt, &end, 0 );
if ( *end ) {
printf ( "Bad server type: %s\n", pxe_type_txt );
return 1;
}
/* Parse net device name */
if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 )
return rc;
/* Parse boot server type */
if ( ( rc = parse_integer ( argv[ optind + 1 ], &pxe_type ) ) != 0 )
return rc;
/* Perform Boot Server Discovery */
if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) {
printf ( "Could not discover boot server on %s: %s\n",
netdev->name, strerror ( rc ) );
return 1;
return rc;
}
return 0;
+27 -25
View File
@@ -16,28 +16,36 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/image.h>
#include <ipxe/crypto.h>
#include <ipxe/md5.h>
#include <ipxe/sha1.h>
/**
* "digest" command syntax message
/** @file
*
* Digest commands
*
* @v argv Argument list
*/
static void digest_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <image name>\n"
"\n"
"Calculate the %s of an image\n",
argv[0], argv[0] );
}
/** "digest" options */
struct digest_options {};
/** "digest" option list */
static struct option_descriptor digest_opts[] = {};
/** "digest" command descriptor */
static struct command_descriptor digest_cmd =
COMMAND_DESC ( struct digest_options, digest_opts, 1, MAX_ARGUMENTS,
"<image> [<image>...]",
"Calculate the digest of an image" );
/**
* The "digest" command
@@ -45,11 +53,11 @@ static void digest_syntax ( char **argv ) {
* @v argc Argument count
* @v argv Argument list
* @v digest Digest algorithm
* @ret rc Exit code
* @ret rc Return status code
*/
static int digest_exec ( int argc, char **argv,
struct digest_algorithm *digest ) {
const char *image_name;
struct digest_options opts;
struct image *image;
uint8_t digest_ctx[digest->ctxsize];
uint8_t digest_out[digest->digestsize];
@@ -59,23 +67,17 @@ static int digest_exec ( int argc, char **argv,
size_t frag_len;
int i;
unsigned j;
int rc;
if ( argc < 2 ||
!strcmp ( argv[1], "--help" ) ||
!strcmp ( argv[1], "-h" ) ) {
digest_syntax ( argv );
return 1;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &digest_cmd, &opts ) ) != 0 )
return rc;
for ( i = 1 ; i < argc ; i++ ) {
image_name = argv[i];
for ( i = optind ; i < argc ; i++ ) {
/* find image */
image = find_image ( image_name );
if ( ! image ) {
printf ( "No such image: %s\n", image_name );
if ( ( rc = parse_image ( argv[i], &image ) ) != 0 )
continue;
}
offset = 0;
len = image->len;
+136 -107
View File
@@ -19,11 +19,13 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <strings.h>
#include <ipxe/fc.h>
#include <ipxe/fcels.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/tables.h>
#include <usr/fcmgmt.h>
@@ -33,36 +35,96 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
static void fcstat_syntax ( char **argv ) {
printf ( "Usage:\n %s\n", argv[0] );
/**
* Parse Fibre Channel port name
*
* @v text Text
* @ret port Fibre Channel port
* @ret rc Return status code
*/
static int parse_fc_port ( const char *text, struct fc_port **port ) {
/* Sanity check */
assert ( text != NULL );
/* Find Fibre Channel port */
*port = fc_port_find ( text );
if ( ! *port ) {
printf ( "\"%s\": no such port\n", text );
return -ENODEV;
}
return 0;
}
/**
* Parse Fibre Channel port ID
*
* @v text Text
* @ret port_id Fibre Channel port ID
* @ret rc Return status code
*/
static int parse_fc_port_id ( const char *text, struct fc_port_id *port_id ) {
int rc;
/* Sanity check */
assert ( text != NULL );
/* Parse port ID */
if ( ( rc = fc_id_aton ( text, port_id ) ) != 0 ) {
printf ( "\"%s\": invalid port ID\n", text );
return -EINVAL;
}
return 0;
}
/**
* Parse Fibre Channel ELS handler name
*
* @v text Text
* @ret handler Fibre Channel ELS handler
* @ret rc Return status code
*/
static int parse_fc_els_handler ( const char *text,
struct fc_els_handler **handler ) {
for_each_table_entry ( (*handler), FC_ELS_HANDLERS ) {
if ( strcasecmp ( (*handler)->name, text ) == 0 )
return 0;
}
printf ( "\"%s\": unrecognised ELS\n", text );
return -ENOENT;
}
/** "fcstat" options */
struct fcstat_options {};
/** "fcstat" option list */
static struct option_descriptor fcstat_opts[] = {};
/** "fcstat" command descriptor */
static struct command_descriptor fcstat_cmd =
COMMAND_DESC ( struct fcstat_options, fcstat_opts, 0, 0,
"", "" );
/**
* The "fcstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int fcstat_exec ( int argc, char **argv ) {
static struct option fcstat_opts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct fcstat_options opts;
struct fc_port *port;
struct fc_peer *peer;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", fcstat_opts,
NULL ) ) >= 0 ) {
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
fcstat_syntax ( argv );
return 1;
}
}
if ( optind != argc ) {
fcstat_syntax ( argv );
return 1;
}
if ( ( rc = parse_options ( argc, argv, &fcstat_cmd, &opts ) ) != 0 )
return rc;
list_for_each_entry ( port, &fc_ports, list )
fcportstat ( port );
@@ -72,105 +134,72 @@ static int fcstat_exec ( int argc, char **argv ) {
return 0;
}
static void fcels_syntax ( char **argv ) {
printf ( "Usage:\n %s [--port <port>] [--id <peer port id>]"
" <command>\n", argv[0] );
}
static struct fc_els_handler * fcels_find_handler ( const char *name ) {
struct fc_els_handler *handler;
for_each_table_entry ( handler, FC_ELS_HANDLERS ) {
if ( strcasecmp ( handler->name, name ) == 0 )
return handler;
}
return NULL;
}
static int fcels_exec ( int argc, char **argv ) {
static struct option fcels_opts[] = {
{ "help", 0, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "id", required_argument, NULL, 'i' },
{ NULL, 0, NULL, 0 },
};
const char *handler_text;
const char *port_text = NULL;
const char *id_text = NULL;
struct fc_els_handler *handler;
/** "fcels" options */
struct fcels_options {
/** Fibre Channel port */
struct fc_port *port;
struct fc_port_id id_buf;
/** Fibre Channel peer port ID */
struct fc_port_id peer_port_id;
};
/** "fcels" option list */
static struct option_descriptor fcels_opts[] = {
OPTION_DESC ( "port", 'p', required_argument,
struct fcels_options, port, parse_fc_port ),
OPTION_DESC ( "id", 'i', required_argument,
struct fcels_options, peer_port_id, parse_fc_port_id ),
};
/** "fcels" command descriptor */
static struct command_descriptor fcels_cmd =
COMMAND_DESC ( struct fcels_options, fcels_opts, 1, 1,
"[--port <port>] [--id <peer_port_id>] <command>", "" );
/**
* The "fcels" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int fcels_exec ( int argc, char **argv ) {
struct fcels_options opts;
struct fc_els_handler *handler;
struct fc_port_id *id;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "hp:i:", fcels_opts,
NULL ) ) >= 0 ) {
switch ( c ) {
case 'p':
port_text = optarg;
break;
case 'i':
id_text = optarg;
break;
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
fcels_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &fcels_cmd, &opts ) ) != 0 )
return rc;
/* Identify ELS */
if ( optind != ( argc - 1 ) ) {
fcels_syntax ( argv );
return 1;
}
handler_text = argv[optind];
handler = fcels_find_handler ( handler_text );
if ( ! handler ) {
printf ( "%s: unrecognised ELS\n", handler_text );
return 1;
}
/* Parse ELS handler */
if ( ( rc = parse_fc_els_handler ( argv[optind], &handler ) ) != 0 )
return rc;
/* Identify port */
if ( port_text ) {
/* Use specified port */
port = fc_port_find ( port_text );
if ( ! port ) {
printf ( "%s: no such port\n", port_text );
return 1;
}
} else {
/* Use first port */
port = list_first_entry ( &fc_ports, struct fc_port, list );
if ( ! port ) {
/* Use first port if no port specified */
if ( ! opts.port ) {
opts.port = list_first_entry ( &fc_ports, struct fc_port,
list );
if ( ! opts.port ) {
printf ( "No ports\n" );
return 1;
return -ENODEV;
}
}
assert ( port != NULL );
/* Identify port ID */
if ( id_text ) {
if ( fc_id_aton ( id_text, &id_buf ) != 0 ) {
printf ( "%s: invalid port ID\n", id_text );
return 1;
}
id = &id_buf;
} else {
if ( fc_link_ok ( &port->link ) &&
! ( port->flags & FC_PORT_HAS_FABRIC ) ) {
id = &port->ptp_link_port_id;
/* Use link peer port ID if no peer port ID specified */
id = &opts.peer_port_id;
if ( memcmp ( id, &fc_empty_port_id, sizeof ( *id ) ) == 0 ) {
if ( fc_link_ok ( &opts.port->link ) &&
! ( opts.port->flags & FC_PORT_HAS_FABRIC ) ) {
id = &opts.port->ptp_link_port_id;
} else {
id = &fc_f_port_id;
}
}
assert ( id != NULL );
if ( fcels ( port, id, handler ) != 0 )
return 1;
/** Issue ELS */
if ( ( rc = fcels ( opts.port, id, handler ) ) != 0 )
return rc;
return 0;
}
+52 -42
View File
@@ -16,9 +16,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/gdbstub.h>
/** @file
@@ -28,71 +33,76 @@
*/
/**
* "gdbstub" command syntax message
* Parse GDB transport name
*
* @v argv Argument list
* @v text Text
* @ret trans GDB transport
* @ret rc Return status code
*/
static void gdbstub_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <transport> [<options>...]\n"
"\n"
"Start remote debugging using one of the following transports:\n"
" serial use serial port (if compiled in)\n"
" udp <interface> use UDP over network interface (if compiled in)\n",
argv[0] );
static int parse_gdb_transport ( const char *text,
struct gdb_transport **trans ) {
/* Sanity check */
assert ( text != NULL );
/* Find transport */
*trans = find_gdb_transport ( text );
if ( ! *trans ) {
printf ( "\"%s\": no such transport (is it compiled in?)\n",
text );
return -ENOTSUP;
}
return 0;
}
/** "gdbstub" options */
struct gdbstub_options {};
/** "gdbstub" option list */
static struct option_descriptor gdbstub_opts[] = {};
/** "gdbstub" command descriptor */
static struct command_descriptor gdbstub_cmd =
COMMAND_DESC ( struct gdbstub_options, gdbstub_opts, 1, MAX_ARGUMENTS,
"<transport> [<options>...]",
"Start remote debugging using one of the following "
"transports:\n"
" serial use serial port (if compiled in)\n"
" udp <interface> use UDP over network interface "
"(if compiled in)" );
/**
* The "gdbstub" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int gdbstub_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *trans_name;
struct gdbstub_options opts;
struct gdb_transport *trans;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
gdbstub_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &gdbstub_cmd, &opts ) ) != 0 )
return rc;
/* At least one argument */
if ( optind == argc ) {
gdbstub_syntax ( argv );
return 1;
}
trans_name = argv[optind++];
/* Parse transport name */
if ( ( rc = parse_gdb_transport ( argv[optind++], &trans ) ) != 0 )
return rc;
/* Initialise transport */
trans = find_gdb_transport ( trans_name );
if ( !trans ) {
printf ( "%s: no such transport (is it compiled in?)\n", trans_name );
return 1;
}
if ( trans->init ) {
if ( trans->init ( argc - optind, &argv[optind] ) != 0 ) {
return 1;
if ( ( rc = trans->init ( argc - optind,
&argv[optind] ) ) != 0 ) {
return rc;
}
}
/* Enter GDB stub */
gdbstub_start ( trans );
return 0;
}
+92 -88
View File
@@ -19,9 +19,11 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/netdevice.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/ifmgmt.h>
#include <hci/ifmgmt_cmd.h>
@@ -31,136 +33,138 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/** Options shared by all if<xxx> commands */
static struct option ifcommon_longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
/**
* Print syntax of if<xxx> command
*
* @v argv Command arguments
* @v verb Verb describing the action of the command
*/
static void ifcommon_syntax ( char **argv, const char *verb ) {
printf ( "Usage:\n"
" %s [<interface>] [<interface>...]\n"
"\n"
"%s the specified network interfaces\n",
argv[0], verb );
}
/**
* Execute if<xxx> command over all network devices
*
* @v payload Command to execute
* @ret rc Exit code
*/
static int ifcommon_do_all ( int ( * payload ) ( struct net_device * ) ) {
struct net_device *netdev;
int rc = 0;
/* Execute payload for each network device */
for_each_netdev ( netdev ) {
if ( payload ( netdev ) != 0 )
rc = 1;
}
return rc;
}
/**
* Execute if<xxx> command over list of network devices
*
* @v payload Command to execute
* @ret rc Exit code
*/
static int ifcommon_do_list ( int ( * payload ) ( struct net_device * ),
char **list, unsigned int count ) {
const char *netdev_name;
struct net_device *netdev;
int rc = 0;
while ( count-- ) {
netdev_name = *(list++);
netdev = find_netdev ( netdev_name );
if ( ! netdev ) {
printf ( "%s: no such interface\n", netdev_name );
rc = 1;
continue;
}
if ( payload ( netdev ) != 0 )
rc = 1;
}
return rc;
}
/** "if<xxx>" command options */
struct option_descriptor ifcommon_opts[0];
/**
* Execute if<xxx> command
*
* @v argc Argument count
* @v argv Argument list
* @v cmd Command descriptor
* @v payload Command to execute
* @v verb Verb describing the action of the command
* @ret rc Exit code
* @ret rc Return status code
*/
int ifcommon_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int ( * payload ) ( struct net_device * ),
const char *verb ) {
int c;
int stop_on_first_success ) {
struct ifcommon_options opts;
struct net_device *netdev;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", ifcommon_longopts,
NULL ) ) >= 0 ) {
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
ifcommon_syntax ( argv, verb );
return 1;
if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
return rc;
if ( optind != argc ) {
/* Treat arguments as a list of interfaces to try */
while ( optind != argc ) {
if ( ( rc = parse_netdev ( argv[optind++],
&netdev ) ) != 0 ) {
continue;
}
if ( ( ( rc = payload ( netdev ) ) == 0 ) &&
stop_on_first_success ) {
return 0;
}
}
} else {
/* Try all interfaces */
rc = -ENODEV;
for_each_netdev ( netdev ) {
if ( ( ( rc = payload ( netdev ) ) == 0 ) &&
stop_on_first_success ) {
return 0;
}
}
}
if ( optind == argc ) {
return ifcommon_do_all ( payload );
} else {
return ifcommon_do_list ( payload, &argv[optind],
( argc - optind ) );
}
return rc;
}
/* "ifopen" command */
/** "ifopen" command descriptor */
static struct command_descriptor ifopen_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]",
"Open network interface(s)" );
/**
* "ifopen" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int ifopen_payload ( struct net_device *netdev ) {
return ifopen ( netdev );
}
/**
* The "ifopen" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int ifopen_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv, ifopen_payload, "Open" );
return ifcommon_exec ( argc, argv, &ifopen_cmd, ifopen_payload, 0 );
}
/* "ifclose" command */
/** "ifclose" command descriptor */
static struct command_descriptor ifclose_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]",
"Close network interface(s)" );
/**
* "ifclose" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int ifclose_payload ( struct net_device *netdev ) {
ifclose ( netdev );
return 0;
}
/**
* The "ifclose" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int ifclose_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv, ifclose_payload, "Close" );
return ifcommon_exec ( argc, argv, &ifclose_cmd, ifclose_payload, 0 );
}
/* "ifstat" command */
/** "ifstat" command descriptor */
static struct command_descriptor ifstat_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]",
"Show network interface(s)" );
/**
* "ifstat" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int ifstat_payload ( struct net_device *netdev ) {
ifstat ( netdev );
return 0;
}
/**
* The "ifstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int ifstat_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv,
ifstat_payload, "Display status of" );
return ifcommon_exec ( argc, argv, &ifstat_cmd, ifstat_payload, 0 );
}
/** Interface management commands */
+157 -316
View File
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <getopt.h>
#include <ipxe/image.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/imgmgmt.h>
/** @file
@@ -34,12 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
enum image_action {
IMG_FETCH = 0,
IMG_LOAD,
IMG_EXEC,
};
/**
* Fill in image command line
*
@@ -74,74 +69,61 @@ static int imgfill_cmdline ( struct image *image, unsigned int nargs,
}
}
/**
* "imgfetch"/"module"/"kernel" command syntax message
*
* @v argv Argument list
*/
static void imgfetch_core_syntax ( char **argv, enum image_action action ) {
static const char *actions[] = {
[IMG_FETCH] = "Fetch",
[IMG_LOAD] = "Fetch and load",
[IMG_EXEC] = "Fetch and execute",
};
/** "imgfetch" options */
struct imgfetch_options {
/** Image name */
const char *name;
};
printf ( "Usage:\n"
" %s [-n|--name <name>] filename [arguments...]\n"
"\n"
"%s executable/loadable image\n",
argv[0], actions[action] );
}
/** "imgfetch" option list */
static struct option_descriptor imgfetch_opts[] = {
OPTION_DESC ( "name", 'n', required_argument,
struct imgfetch_options, name, parse_string ),
};
/** "imgfetch" command descriptor */
static struct command_descriptor imgfetch_cmd =
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
"[--name <name>] <image_url> [<arguments>...]",
"Fetch image" );
/** "kernel" command descriptor */
static struct command_descriptor kernel_cmd =
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
"[--name <name>] <image_url> [<arguments>...]",
"Fetch and load image" );
/** "chain" command descriptor */
static struct command_descriptor chain_cmd =
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
"[--name <name>] <image_url> [<arguments>...]",
"Fetch and execute image" );
/**
* The "imgfetch"/"module"/"kernel" command body
* The "imgfetch" and friends command body
*
* @v image_type Image type to assign (or NULL)
* @v load Image will be automatically loaded after fetching
* @v argc Argument count
* @v argv Argument list
* @v cmd Command descriptor
* @v image_register Image registration action
* @ret rc Return status code
*/
static int imgfetch_core_exec ( struct image_type *image_type,
enum image_action action,
int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ "name", required_argument, NULL, 'n' },
{ NULL, 0, NULL, 0 },
};
static int imgfetch_core_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int ( * image_register ) ( struct image * ) ) {
struct imgfetch_options opts;
struct image *image;
const char *name = NULL;
char *filename;
int ( * image_register ) ( struct image *image );
int c;
char *uri_string;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "hn:",
longopts, NULL ) ) >= 0 ) {
switch ( c ) {
case 'n':
/* Set image name */
name = optarg;
break;
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgfetch_core_syntax ( argv, action );
return -EINVAL;
}
}
if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
return rc;
/* Need at least a filename remaining after the options */
if ( optind == argc ) {
imgfetch_core_syntax ( argv, action );
return -EINVAL;
}
filename = argv[optind++];
if ( ! name )
name = basename ( filename );
/* Parse URI string */
uri_string = argv[optind];
if ( ! opts.name )
opts.name = basename ( uri_string );
/* Allocate image */
image = alloc_image();
@@ -151,37 +133,18 @@ static int imgfetch_core_exec ( struct image_type *image_type,
}
/* Fill in image name */
if ( name ) {
if ( ( rc = image_set_name ( image, name ) ) != 0 )
return rc;
}
/* Set image type (if specified) */
image->type = image_type;
if ( ( rc = image_set_name ( image, opts.name ) ) != 0 )
return rc;
/* Fill in command line */
if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
&argv[optind] ) ) != 0 )
if ( ( rc = imgfill_cmdline ( image, ( argc - optind - 1 ),
&argv[ optind + 1 ] ) ) != 0 )
return rc;
/* Fetch the image */
switch ( action ) {
case IMG_FETCH:
image_register = register_image;
break;
case IMG_LOAD:
image_register = register_and_autoload_image;
break;
case IMG_EXEC:
image_register = register_and_autoexec_image;
break;
default:
assert ( 0 );
return -EINVAL;
}
if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) {
if ( ( rc = imgfetch ( image, uri_string, image_register ) ) != 0 ) {
printf ( "Could not fetch %s: %s\n",
filename, strerror ( rc ) );
uri_string, strerror ( rc ) );
image_put ( image );
return rc;
}
@@ -195,16 +158,12 @@ static int imgfetch_core_exec ( struct image_type *image_type,
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgfetch_exec ( int argc, char **argv ) {
int rc;
if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH,
argc, argv ) ) != 0 )
return rc;
return 0;
return imgfetch_core_exec ( argc, argv, &imgfetch_cmd,
register_image );
}
/**
@@ -212,15 +171,12 @@ static int imgfetch_exec ( int argc, char **argv ) {
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int kernel_exec ( int argc, char **argv ) {
int rc;
if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 )
return rc;
return 0;
return imgfetch_core_exec ( argc, argv, &kernel_cmd,
register_and_autoload_image );
}
/**
@@ -228,327 +184,211 @@ static int kernel_exec ( int argc, char **argv ) {
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int chain_exec ( int argc, char **argv) {
int rc;
if ( ( rc = imgfetch_core_exec ( NULL, IMG_EXEC, argc, argv ) ) != 0 )
return rc;
return 0;
return imgfetch_core_exec ( argc, argv, &chain_cmd,
register_and_autoexec_image );
}
/**
* "imgload" command syntax message
*
* @v argv Argument list
*/
static void imgload_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <image name>\n"
"\n"
"Load executable/loadable image\n",
argv[0] );
}
/** "imgload" options */
struct imgload_options {};
/** "imgload" option list */
static struct option_descriptor imgload_opts[] = {};
/** "imgload" command descriptor */
static struct command_descriptor imgload_cmd =
COMMAND_DESC ( struct imgload_options, imgload_opts, 1, 1,
"<image>", "Load image" );
/**
* The "imgload" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgload_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct imgload_options opts;
struct image *image;
const char *name;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgload_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &imgload_cmd, &opts ) ) != 0 )
return rc;
/* Need exactly one image name remaining after the options */
if ( optind != ( argc - 1 ) ) {
imgload_syntax ( argv );
return 1;
}
name = argv[optind];
/* Parse image name */
if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
return rc;
/* Load all specified images */
image = find_image ( name );
if ( ! image ) {
printf ( "No such image: %s\n", name );
return 1;
}
/* Load image */
if ( ( rc = imgload ( image ) ) != 0 ) {
printf ( "Could not load %s: %s\n", name, strerror ( rc ) );
printf ( "Could not load %s: %s\n",
image->name, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* "imgargs" command syntax message
*
* @v argv Argument list
*/
static void imgargs_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <image name> [<arguments>...]\n"
"\n"
"Set arguments for executable/loadable image\n",
argv[0] );
}
/** "imgargs" options */
struct imgargs_options {};
/** "imgargs" option list */
static struct option_descriptor imgargs_opts[] = {};
/** "imgargs" command descriptor */
static struct command_descriptor imgargs_cmd =
COMMAND_DESC ( struct imgargs_options, imgargs_opts, 1, MAX_ARGUMENTS,
"<image> [<arguments>...]",
"Set arguments for image" );
/**
* The "imgargs" command body
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgargs_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct imgargs_options opts;
struct image *image;
const char *name;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgargs_syntax ( argv );
return 1;
}
}
/* Need at least an image name remaining after the options */
if ( optind == argc ) {
imgargs_syntax ( argv );
return 1;
}
name = argv[optind++];
/* Fill in command line */
image = find_image ( name );
if ( ! image ) {
printf ( "No such image: %s\n", name );
return 1;
}
if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
&argv[optind] ) ) != 0 )
if ( ( rc = parse_options ( argc, argv, &imgargs_cmd, &opts ) ) != 0 )
return rc;
/* Parse image name */
if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
return rc;
/* Fill in command line */
if ( ( rc = imgfill_cmdline ( image, ( argc - optind - 1 ),
&argv[ optind + 1 ] ) ) != 0 )
return rc;
return 0;
}
/**
* "imgexec" command syntax message
*
* @v argv Argument list
*/
static void imgexec_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <image name>\n"
"\n"
"Execute executable/loadable image\n",
argv[0] );
}
/** "imgexec" options */
struct imgexec_options {};
/** "imgexec" option list */
static struct option_descriptor imgexec_opts[] = {};
/** "imgexec" command descriptor */
static struct command_descriptor imgexec_cmd =
COMMAND_DESC ( struct imgexec_options, imgexec_opts, 0, 1,
"[<image>]", "Execute image" );
/**
* The "imgexec" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgexec_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct imgexec_options opts;
struct image *image;
const char *name = NULL;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgexec_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &imgexec_cmd, &opts ) ) != 0 )
return rc;
/* Need no more than one image name */
if ( optind != argc )
name = argv[optind++];
if ( optind != argc ) {
imgexec_syntax ( argv );
return 1;
}
/* Execute specified image */
if ( name ) {
image = find_image ( name );
if ( ! image ) {
printf ( "No such image: %s\n", name );
return 1;
}
/* Parse image name */
if ( optind < argc ) {
if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
return rc;
} else {
image = imgautoselect();
if ( ! image ) {
printf ( "No (unique) loaded image\n" );
return 1;
return -ENOTTY;
}
}
/* Execute image */
if ( ( rc = imgexec ( image ) ) != 0 ) {
printf ( "Could not execute %s: %s\n",
image->name, strerror ( rc ) );
return 1;
return rc;
}
return 0;
}
/**
* "imgstat" command syntax message
*
* @v argv Argument list
*/
static void imgstat_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s\n"
"\n"
"List executable/loadable images\n",
argv[0] );
}
/** "imgstat" options */
struct imgstat_options {};
/** "imgstat" option list */
static struct option_descriptor imgstat_opts[] = {};
/** "imgstat" command descriptor */
static struct command_descriptor imgstat_cmd =
COMMAND_DESC ( struct imgstat_options, imgstat_opts, 0, 0,
"", "List images" );
/**
* The "imgstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgstat_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct imgstat_options opts;
struct image *image;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgstat_syntax ( argv );
return 1;
}
}
/* No arguments */
if ( optind != argc ) {
imgstat_syntax ( argv );
return 1;
}
if ( ( rc = parse_options ( argc, argv, &imgstat_cmd, &opts ) ) != 0 )
return rc;
/* Show status of all images */
for_each_image ( image ) {
imgstat ( image );
}
return 0;
}
/**
* "imgstat" command syntax message
*
* @v argv Argument list
*/
static void imgfree_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s [<image name>]\n"
"\n"
"Free one or all executable/loadable images\n",
argv[0] );
}
/** "imgfree" options */
struct imgfree_options {};
/** "imgfree" option list */
static struct option_descriptor imgfree_opts[] = {};
/** "imgfree" command descriptor */
static struct command_descriptor imgfree_cmd =
COMMAND_DESC ( struct imgfree_options, imgfree_opts, 0, 1,
"[<image>]", "Free image(s)" );
/**
* The "imgfree" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int imgfree_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
struct imgfree_options opts;
struct image *image;
struct image *tmp;
const char *name = NULL;
int c;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
imgfree_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &imgfree_cmd, &opts ) ) != 0 )
return rc;
/* Need no more than one image name */
if ( optind != argc )
name = argv[optind++];
if ( optind != argc ) {
imgfree_syntax ( argv );
return 1;
}
if ( name ) {
/* Free specified image (may leak) */
image = find_image ( name );
if ( ! image ) {
printf ( "No such image: %s\n", name );
return 1;
}
if ( optind < argc ) {
/* Free specified image */
if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
return rc;
imgfree ( image );
} else {
/* Free all images */
@@ -556,6 +396,7 @@ static int imgfree_exec ( int argc, char **argv ) {
imgfree ( image );
}
}
return 0;
}
+45 -6
View File
@@ -21,11 +21,28 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/netdevice.h>
#include <ipxe/net80211.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/iwmgmt.h>
#include <hci/ifmgmt_cmd.h>
/* "iwstat" command */
/** @file
*
* Wireless interface management commands
*
*/
/** "iwstat" command descriptor */
static struct command_descriptor iwstat_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]",
"Show wireless interface(s)" );
/**
* "iwstat" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int iwstat_payload ( struct net_device *netdev ) {
struct net80211_device *dev = net80211_get ( netdev );
@@ -35,13 +52,29 @@ static int iwstat_payload ( struct net_device *netdev ) {
return 0;
}
/**
* The "iwstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int iwstat_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv,
iwstat_payload, "Display wireless status of" );
return ifcommon_exec ( argc, argv, &iwstat_cmd, iwstat_payload, 0 );
}
/* "iwlist" command */
/** "iwlist" command descriptor */
static struct command_descriptor iwlist_cmd =
COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
"[<interface>...]",
"List wireless networks" );
/**
* "iwlist" payload
*
* @v netdev Network device
* @ret rc Return status code
*/
static int iwlist_payload ( struct net_device *netdev ) {
struct net80211_device *dev = net80211_get ( netdev );
@@ -51,9 +84,15 @@ static int iwlist_payload ( struct net_device *netdev ) {
return 0;
}
/**
* The "iwlist" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int iwlist_exec ( int argc, char **argv ) {
return ifcommon_exec ( argc, argv, iwlist_payload,
"List wireless networks available via" );
return ifcommon_exec ( argc, argv, &iwlist_cmd, iwlist_payload, 0 );
}
/** Wireless interface management commands */
+50 -6
View File
@@ -1,28 +1,72 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/login_ui.h>
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Login commands
*
*/
/** "login" options */
struct login_options {};
/** "login" option list */
static struct option_descriptor login_opts[] = {};
/** "login" command descriptor */
static struct command_descriptor login_cmd =
COMMAND_DESC ( struct login_options, login_opts, 0, 0,
"", "Prompt for login credentials" );
/**
* "login" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int login_exec ( int argc, char **argv ) {
struct login_options opts;
int rc;
if ( argc > 1 ) {
printf ( "Usage: %s\n"
"Prompt for login credentials\n", argv[0] );
return 1;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &login_cmd, &opts ) ) != 0 )
return rc;
/* Show login UI */
if ( ( rc = login_ui() ) != 0 ) {
printf ( "Could not set credentials: %s\n",
strerror ( rc ) );
return 1;
return rc;
}
return 0;
}
/** Login commands */
struct command login_command __command = {
.name = "login",
.exec = login_exec,
+42 -59
View File
@@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <getopt.h>
#include <ipxe/netdevice.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/if_ether.h>
#include <usr/lotest.h>
@@ -33,81 +34,63 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
static void lotest_syntax ( char **argv ) {
printf ( "Usage:\n %s <sending interface> <receiving interface>\n",
argv[0] );
}
/** "lotest" options */
struct lotest_options {
/** MTU */
unsigned int mtu;
};
/** "lotest" option list */
static struct option_descriptor lotest_opts[] = {
OPTION_DESC ( "mtu", 'm', required_argument,
struct lotest_options, mtu, parse_integer ),
};
/** "lotest" command descriptor */
static struct command_descriptor lotest_cmd =
COMMAND_DESC ( struct lotest_options, lotest_opts, 2, 2,
"[--mtu <mtu>] <sending_interface> "
"<receiving_interface>", "" );
/**
* "lotest" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int lotest_exec ( int argc, char **argv ) {
static struct option lotest_opts[] = {
{ "help", 0, NULL, 'h' },
{ "mtu", required_argument, NULL, 'm' },
{ NULL, 0, NULL, 0 },
};
const char *sender_name;
const char *receiver_name;
const char *mtu_text = NULL;
struct lotest_options opts;
struct net_device *sender;
struct net_device *receiver;
char *endp;
size_t mtu;
int c;
int rc;
/* Parse command line */
while ( ( c = getopt_long ( argc, argv, "hm:", lotest_opts,
NULL ) ) >= 0 ) {
switch ( c ) {
case 'm':
mtu_text = optarg;
break;
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
lotest_syntax ( argv );
return 1;
}
}
if ( optind != ( argc - 2 ) ) {
lotest_syntax ( argv );
return 1;
}
sender_name = argv[optind];
receiver_name = argv[optind + 1];
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &lotest_cmd, &opts ) ) != 0 )
return rc;
/* Identify network devices */
sender = find_netdev ( sender_name );
if ( ! sender ) {
printf ( "%s: no such interface\n", sender_name );
return 1;
}
receiver = find_netdev ( receiver_name );
if ( ! receiver ) {
printf ( "%s: no such interface\n", receiver_name );
return 1;
}
/* Parse sending interface name */
if ( ( rc = parse_netdev ( argv[optind], &sender ) ) != 0 )
return rc;
/* Identify MTU */
if ( mtu_text ) {
mtu = strtoul ( mtu_text, &endp, 10 );
if ( *endp ) {
printf ( "%s: invalid MTU\n", mtu_text );
return 1;
}
} else {
mtu = ETH_MAX_MTU;
}
/* Parse receiving interface name */
if ( ( rc = parse_netdev ( argv[ optind + 1 ], &receiver ) ) != 0 )
return rc;
/* Use default MTU if none specified */
if ( ! opts.mtu )
opts.mtu = ETH_MAX_MTU;
/* Perform loopback test */
if ( ( rc = loopback_test ( sender, receiver, mtu ) ) != 0 ) {
if ( ( rc = loopback_test ( sender, receiver, opts.mtu ) ) != 0 ) {
printf ( "Test failed: %s\n", strerror ( rc ) );
return 1;
return rc;
}
return 0;
}
/** Loopback testing commands */
struct command lotest_command __command = {
.name = "lotest",
.exec = lotest_exec,
+121 -25
View File
@@ -1,3 +1,21 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
@@ -6,42 +24,96 @@
#include <getopt.h>
#include <ipxe/settings.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Non-volatile option commands
*
*/
/** "show" options */
struct show_options {};
/** "show" option list */
static struct option_descriptor show_opts[] = {};
/** "show" command descriptor */
static struct command_descriptor show_cmd =
COMMAND_DESC ( struct show_options, show_opts, 1, 1,
"<setting>", "" );
/**
* "show" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int show_exec ( int argc, char **argv ) {
struct show_options opts;
const char *name;
char buf[256];
int rc;
if ( argc != 2 ) {
printf ( "Syntax: %s <identifier>\n", argv[0] );
return 1;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &show_cmd, &opts ) ) != 0 )
return rc;
if ( ( rc = fetchf_named_setting ( argv[1], buf,
sizeof ( buf ) ) ) < 0 ){
/* Parse setting name */
name = argv[optind];
/* Fetch setting */
if ( ( rc = fetchf_named_setting ( name, buf,
sizeof ( buf ) ) ) < 0 ) {
printf ( "Could not find \"%s\": %s\n",
argv[1], strerror ( rc ) );
return 1;
name, strerror ( rc ) );
return rc;
}
printf ( "%s = %s\n", argv[1], buf );
/* Print setting value */
printf ( "%s = %s\n", name, buf );
return 0;
}
/** "set" options */
struct set_options {};
/** "set" option list */
static struct option_descriptor set_opts[] = {};
/** "set" command descriptor */
static struct command_descriptor set_cmd =
COMMAND_DESC ( struct set_options, set_opts, 1, MAX_ARGUMENTS,
"<setting> <value>", "" );
/**
* "set" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int set_exec ( int argc, char **argv ) {
struct set_options opts;
const char *name;
size_t len;
int i;
int rc;
if ( argc < 3 ) {
printf ( "Syntax: %s <identifier> <value>\n", argv[0] );
return 1;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &set_cmd, &opts ) ) != 0 )
return rc;
/* Parse setting name */
name = argv[optind];
/* Determine total length of command line */
len = 1; /* NUL */
for ( i = 2 ; i < argc ; i++ )
for ( i = optind + 1 ; i < argc ; i++ )
len += ( 1 /* possible space */ + strlen ( argv[i] ) );
{
@@ -50,39 +122,63 @@ static int set_exec ( int argc, char **argv ) {
/* Assemble command line */
buf[0] = '\0';
for ( i = 2 ; i < argc ; i++ ) {
for ( i = optind + 1 ; i < argc ; i++ ) {
ptr += sprintf ( ptr, "%s%s", ( buf[0] ? " " : "" ),
argv[i] );
}
assert ( ptr < ( buf + len ) );
if ( ( rc = storef_named_setting ( argv[1], buf ) ) != 0 ) {
if ( ( rc = storef_named_setting ( name, buf ) ) != 0 ) {
printf ( "Could not set \"%s\"=\"%s\": %s\n",
argv[1], buf, strerror ( rc ) );
return 1;
name, buf, strerror ( rc ) );
return rc;
}
}
return 0;
}
/** "clear" options */
struct clear_options {};
/** "clear" option list */
static struct option_descriptor clear_opts[] = {};
/** "clear" command descriptor */
static struct command_descriptor clear_cmd =
COMMAND_DESC ( struct clear_options, clear_opts, 1, 1,
"<setting>", "" );
/**
* "clear" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int clear_exec ( int argc, char **argv ) {
struct clear_options opts;
const char *name;
int rc;
if ( argc != 2 ) {
printf ( "Syntax: %s <identifier>\n", argv[0] );
return 1;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &clear_cmd, &opts ) ) != 0 )
return rc;
if ( ( rc = delete_named_setting ( argv[1] ) ) != 0 ) {
/* Parse setting name */
name = argv[optind];
/* Clear setting */
if ( ( rc = delete_named_setting ( name ) ) != 0 ) {
printf ( "Could not clear \"%s\": %s\n",
argv[1], strerror ( rc ) );
return 1;
name, strerror ( rc ) );
return rc;
}
return 0;
}
/** Non-volatile option commands */
struct command nvo_commands[] __command = {
{
.name = "show",
+17 -34
View File
@@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/route.h>
/** @file
@@ -29,52 +30,34 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/**
* "route" command syntax message
*
* @v argv Argument list
*/
static void route_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s\n"
"\n"
"Displays the routing table\n",
argv[0] );
}
/** "route" options */
struct route_options {};
/** "route" option list */
static struct option_descriptor route_opts[] = {};
/** "route" command descriptor */
static struct command_descriptor route_cmd =
COMMAND_DESC ( struct route_options, route_opts, 0, 0,
"", "Display the routing table" );
/**
* The "route" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int route_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
int c;
struct route_options opts;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
route_syntax ( argv );
return 1;
}
}
if ( optind != argc ) {
route_syntax ( argv );
return 1;
}
if ( ( rc = parse_options ( argc, argv, &route_cmd, &opts ) ) != 0 )
return rc;
route();
return 0;
}
+41 -33
View File
@@ -1,69 +1,77 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/autoboot.h>
FILE_LICENCE ( GPL2_OR_LATER );
/**
* "sanboot" command syntax message
/** @file
*
* SAN commands
*
* @v argv Argument list
*/
static void sanboot_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <root-path>\n"
"\n"
"Boot from SAN target\n",
argv[0] );
}
/** "sanboot" options */
struct sanboot_options {};
/** "sanboot" option list */
static struct option_descriptor sanboot_opts[] = {};
/** "sanboot" command descriptor */
static struct command_descriptor sanboot_cmd =
COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1,
"<root-path>", "Boot from SAN target" );
/**
* The "sanboot" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
* @ret rc Return status code
*/
static int sanboot_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *root_path = NULL;
int c;
struct sanboot_options opts;
const char *root_path;
int rc;
/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
sanboot_syntax ( argv );
return 1;
}
}
if ( ( rc = parse_options ( argc, argv, &sanboot_cmd, &opts ) ) != 0 )
return rc;
/* Need exactly one image name remaining after the options */
if ( optind != ( argc - 1 ) ) {
sanboot_syntax ( argv );
return 1;
}
/* Parse root path */
root_path = argv[optind];
/* Boot from root path */
if ( ( rc = boot_root_path ( root_path ) ) != 0 ) {
printf ( "Could not boot from %s: %s\n",
root_path, strerror ( rc ) );
return 1;
return rc;
}
return 0;
}
/** SAN commands */
struct command sanboot_command __command = {
.name = "sanboot",
.exec = sanboot_exec,
+63 -27
View File
@@ -19,29 +19,50 @@
* Shao Miller <shao.miller@yrdsb.edu.on.ca>.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/nap.h>
#include <ipxe/timer.h>
static int time_exec ( int argc, char **argv ) {
unsigned long start;
int rc, secs;
/** @file
*
* Time commands
*
*/
if ( argc == 1 ||
!strcmp ( argv[1], "--help" ) ||
!strcmp ( argv[1], "-h" ) )
{
printf ( "Usage:\n"
" %s <command>\n"
"\n"
"Time a command\n",
argv[0] );
return 1;
}
/** "time" options */
struct time_options {};
/** "time" option list */
static struct option_descriptor time_opts[] = {};
/** "time" command descriptor */
static struct command_descriptor time_cmd =
COMMAND_DESC ( struct time_options, time_opts, 1, MAX_ARGUMENTS,
"<command>", "Time a command" );
/**
* "time" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int time_exec ( int argc, char **argv ) {
struct time_options opts;
unsigned long start;
int secs;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &time_cmd, &opts ) ) != 0 )
return rc;
start = currticks();
rc = execv ( argv[1], argv + 1 );
@@ -52,25 +73,39 @@ static int time_exec ( int argc, char **argv ) {
return rc;
}
/** "time" command */
struct command time_command __command = {
.name = "time",
.exec = time_exec,
};
static int sleep_exec ( int argc, char **argv ) {
unsigned long start, delay;
/** "sleep" options */
struct sleep_options {};
/** "sleep" option list */
static struct option_descriptor sleep_opts[] = {};
/** "sleep" command descriptor */
static struct command_descriptor sleep_cmd =
COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1,
"<seconds>", "Sleep for <seconds> seconds" );
/**
* "sleep" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int sleep_exec ( int argc, char **argv ) {
struct sleep_options opts;
unsigned long start, delay;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 )
return rc;
if ( argc == 1 ||
!strcmp ( argv[1], "--help" ) ||
!strcmp ( argv[1], "-h" ))
{
printf ( "Usage:\n"
" %s <seconds>\n"
"\n"
"Sleep for <seconds> seconds\n",
argv[0] );
return 1;
}
start = currticks();
delay = strtoul ( argv[1], NULL, 0 ) * ticks_per_sec();
while ( ( currticks() - start ) <= delay )
@@ -78,6 +113,7 @@ static int sleep_exec ( int argc, char **argv ) {
return 0;
}
/** "sleep" command */
struct command sleep_command __command = {
.name = "sleep",
.exec = sleep_exec,
+141
View File
@@ -0,0 +1,141 @@
/*
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <ipxe/netdevice.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/vlan.h>
/** @file
*
* VLAN commands
*
*/
/** "vcreate" options */
struct vcreate_options {
/** VLAN tag */
unsigned int tag;
/** VLAN default priority */
unsigned int priority;
};
/** "vcreate" option list */
static struct option_descriptor vcreate_opts[] = {
OPTION_DESC ( "tag", 't', required_argument,
struct vcreate_options, tag, parse_integer ),
OPTION_DESC ( "priority", 'p', required_argument,
struct vcreate_options, priority, parse_integer ),
};
/** "vcreate" command descriptor */
static struct command_descriptor vcreate_cmd =
COMMAND_DESC ( struct vcreate_options, vcreate_opts, 1, 1,
"--tag <tag> [--priority <priority>] "
"<trunk interface>",
"Create a VLAN interface" );
/**
* "vcreate" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int vcreate_exec ( int argc, char **argv ) {
struct vcreate_options opts;
struct net_device *trunk;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &vcreate_cmd, &opts ) ) != 0 )
return rc;
/* Parse trunk interface */
if ( ( rc = parse_netdev ( argv[optind], &trunk ) ) != 0 )
return rc;
/* Create VLAN device */
if ( ( rc = vlan_create ( trunk, opts.tag, opts.priority ) ) != 0 ) {
printf ( "Could not create VLAN device: %s\n",
strerror ( rc ) );
return rc;
}
return 0;
}
/** "vdestroy" options */
struct vdestroy_options {};
/** "vdestroy" option list */
static struct option_descriptor vdestroy_opts[] = {};
/** "vdestroy" command descriptor */
static struct command_descriptor vdestroy_cmd =
COMMAND_DESC ( struct vdestroy_options, vdestroy_opts, 1, 1,
"<VLAN interface>",
"Destroy a VLAN interface" );
/**
* "vdestroy" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int vdestroy_exec ( int argc, char **argv ) {
struct vdestroy_options opts;
struct net_device *netdev;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &vdestroy_cmd, &opts ) ) != 0 )
return rc;
/* Parse trunk interface */
if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 )
return rc;
/* Destroy VLAN device */
if ( ( rc = vlan_destroy ( netdev ) ) != 0 ) {
printf ( "Could not destroy VLAN device: %s\n",
strerror ( rc ) );
return rc;
}
return 0;
}
/** VLAN commands */
struct command vlan_commands[] __command = {
{
.name = "vcreate",
.exec = vcreate_exec,
},
{
.name = "vdestroy",
.exec = vdestroy_exec,
},
};
+56 -29
View File
@@ -21,8 +21,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <readline/readline.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/shell.h>
/** @file
@@ -34,29 +36,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** The shell prompt string */
static const char shell_prompt[] = "iPXE> ";
/** Flag set in order to exit shell */
static int exit_flag = 0;
/** "exit" command body */
static int exit_exec ( int argc, char **argv __unused ) {
if ( argc == 1 ) {
exit_flag = 1;
} else {
printf ( "Usage: exit\n"
"Exits the command shell\n" );
}
return 0;
}
/** "exit" command definition */
struct command exit_command __command = {
.name = "exit",
.exec = exit_exec,
};
/** "help" command body */
/**
* "help" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int help_exec ( int argc __unused, char **argv __unused ) {
struct command *command;
unsigned int hpos = 0;
@@ -78,7 +64,7 @@ static int help_exec ( int argc __unused, char **argv __unused ) {
return 0;
}
/** "help" command definition */
/** "help" command */
struct command help_command __command = {
.name = "help",
.exec = help_exec,
@@ -88,15 +74,56 @@ struct command help_command __command = {
* Start command shell
*
*/
void shell ( void ) {
int shell ( void ) {
char *line;
int rc = 0;
exit_flag = 0;
while ( ! exit_flag ) {
do {
line = readline ( shell_prompt );
if ( line ) {
system ( line );
rc = system ( line );
free ( line );
}
}
} while ( ! shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) );
return rc;
}
/** "shell" options */
struct shell_options {};
/** "shell" option list */
static struct option_descriptor shell_opts[] = {};
/** "shell" command descriptor */
static struct command_descriptor shell_cmd =
COMMAND_DESC ( struct shell_options, shell_opts, 0, 0,
"", "" );
/**
* "shell" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int shell_exec ( int argc, char **argv ) {
struct shell_options opts;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &shell_cmd, &opts ) ) != 0 )
return rc;
/* Start shell */
if ( ( rc = shell() ) != 0 )
return rc;
return 0;
}
/** "shell" command */
struct command shell_command __command = {
.name = "shell",
.exec = shell_exec,
};
+198 -30
View File
@@ -27,12 +27,110 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/image.h>
#include <ipxe/shell.h>
struct image_type script_image_type __image_type ( PROBE_NORMAL );
/** Currently running script
*
* This is a global in order to allow goto_exec() to update the
* offset.
*/
static struct image *script;
/** Offset within current script
*
* This is a global in order to allow goto_exec() to update the
* offset.
*/
static size_t script_offset;
/**
* Process script lines
*
* @v process_line Line processor
* @v terminate Termination check
* @ret rc Return status code
*/
static int process_script ( int ( * process_line ) ( const char *line ),
int ( * terminate ) ( int rc ) ) {
off_t eol;
size_t len;
int rc;
script_offset = 0;
do {
/* Find length of next line, excluding any terminating '\n' */
eol = memchr_user ( script->data, script_offset, '\n',
( script->len - script_offset ) );
if ( eol < 0 )
eol = script->len;
len = ( eol - script_offset );
/* Copy line, terminate with NUL, and execute command */
{
char cmdbuf[ len + 1 ];
copy_from_user ( cmdbuf, script->data,
script_offset, len );
cmdbuf[len] = '\0';
DBG ( "$ %s\n", cmdbuf );
/* Move to next line */
script_offset += ( len + 1 );
/* Process line */
rc = process_line ( cmdbuf );
if ( terminate ( rc ) )
return rc;
}
} while ( script_offset < script->len );
return rc;
}
/**
* Terminate script processing on shell exit or command failure
*
* @v rc Line processing status
* @ret terminate Terminate script processing
*/
static int terminate_on_exit_or_failure ( int rc ) {
return ( shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) ||
( rc != 0 ) );
}
/**
* Execute script line
*
* @v line Line of script
* @ret rc Return status code
*/
static int script_exec_line ( const char *line ) {
int rc;
/* Skip label lines */
if ( line[0] == ':' )
return 0;
/* Execute command */
if ( ( rc = system ( line ) ) != 0 )
return rc;
return 0;
}
/**
* Execute script
*
@@ -40,9 +138,8 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL );
* @ret rc Return status code
*/
static int script_exec ( struct image *image ) {
size_t offset = 0;
off_t eol;
size_t len;
struct image *saved_script;
size_t saved_offset;
int rc;
/* Temporarily de-register image, so that a "boot" command
@@ -50,36 +147,19 @@ static int script_exec ( struct image *image ) {
*/
unregister_image ( image );
while ( offset < image->len ) {
/* Find length of next line, excluding any terminating '\n' */
eol = memchr_user ( image->data, offset, '\n',
( image->len - offset ) );
if ( eol < 0 )
eol = image->len;
len = ( eol - offset );
/* Preserve state of any currently-running script */
saved_script = script;
saved_offset = script_offset;
/* Copy line, terminate with NUL, and execute command */
{
char cmdbuf[ len + 1 ];
/* Initialise state for this script */
script = image;
copy_from_user ( cmdbuf, image->data, offset, len );
cmdbuf[len] = '\0';
DBG ( "$ %s\n", cmdbuf );
if ( ( rc = system ( cmdbuf ) ) != 0 ) {
DBG ( "Command \"%s\" failed: %s\n",
cmdbuf, strerror ( rc ) );
goto done;
}
}
/* Move to next line */
offset += ( len + 1 );
}
/* Process script */
rc = process_script ( script_exec_line, terminate_on_exit_or_failure );
rc = 0;
done:
/* Re-register image and return */
/* Restore saved state, re-register image, and return */
script_offset = saved_offset;
script = saved_script;
register_image ( image );
return rc;
}
@@ -129,3 +209,91 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
.load = script_load,
.exec = script_exec,
};
/** "goto" options */
struct goto_options {};
/** "goto" option list */
static struct option_descriptor goto_opts[] = {};
/** "goto" command descriptor */
static struct command_descriptor goto_cmd =
COMMAND_DESC ( struct goto_options, goto_opts, 1, 1,
"<label>", "" );
/**
* Current "goto" label
*
* Valid only during goto_exec(). Consider this part of a closure.
*/
static const char *goto_label;
/**
* Check for presence of label
*
* @v line Script line
* @ret rc Return status code
*/
static int goto_find_label ( const char *line ) {
if ( line[0] != ':' )
return -ENOENT;
if ( strcmp ( goto_label, &line[1] ) != 0 )
return -ENOENT;
return 0;
}
/**
* Terminate script processing when label is found
*
* @v rc Line processing status
* @ret terminate Terminate script processing
*/
static int terminate_on_label_found ( int rc ) {
return ( rc == 0 );
}
/**
* "goto" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int goto_exec ( int argc, char **argv ) {
struct goto_options opts;
size_t saved_offset;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &goto_cmd, &opts ) ) != 0 )
return rc;
/* Sanity check */
if ( ! script ) {
printf ( "Not in a script\n" );
return -ENOTTY;
}
/* Parse label */
goto_label = argv[optind];
/* Find label */
saved_offset = script_offset;
if ( ( rc = process_script ( goto_find_label,
terminate_on_label_found ) ) != 0 ) {
script_offset = saved_offset;
return rc;
}
/* Terminate processing of current command */
shell_stop ( SHELL_STOP_COMMAND );
return 0;
}
/** "goto" command */
struct command goto_command __command = {
.name = "goto",
.exec = goto_exec,
};
+74
View File
@@ -272,6 +272,8 @@ extern void dbg_autocolourise ( unsigned long id );
extern void dbg_decolourise ( void );
extern void dbg_hex_dump_da ( unsigned long dispaddr,
const void *data, unsigned long len );
extern void dbg_md5_da ( unsigned long dispaddr,
const void *data, unsigned long len );
extern void dbg_pause ( void );
extern void dbg_more ( void );
@@ -349,6 +351,37 @@ int __debug_disable;
DBG_HDA_IF ( level, _data, _data, len ); \
} while ( 0 )
/**
* Print an MD5 checksum if we are at a certain debug level
*
* @v level Debug level
* @v dispaddr Display address
* @v data Data to print
* @v len Length of data
*/
#define DBG_MD5A_IF( level, dispaddr, data, len ) do { \
if ( DBG_ ## level ) { \
union { \
unsigned long ul; \
typeof ( dispaddr ) raw; \
} da; \
da.raw = dispaddr; \
dbg_md5_da ( da.ul, data, len ); \
} \
} while ( 0 )
/**
* Print an MD5 checksum if we are at a certain debug level
*
* @v level Debug level
* @v data Data to print
* @v len Length of data
*/
#define DBG_MD5_IF( level, data, len ) do { \
const void *_data = data; \
DBG_MD5A_IF ( level, _data, _data, len ); \
} while ( 0 )
/**
* Prompt for key press if we are at a certain debug level
*
@@ -419,6 +452,18 @@ int __debug_disable;
DBG_DC_IF ( level ); \
} while ( 0 )
#define DBGC_MD5A_IF( level, id, ... ) do { \
DBG_AC_IF ( level, id ); \
DBG_MD5A_IF ( level, __VA_ARGS__ ); \
DBG_DC_IF ( level ); \
} while ( 0 )
#define DBGC_MD5_IF( level, id, ... ) do { \
DBG_AC_IF ( level, id ); \
DBG_MD5_IF ( level, __VA_ARGS__ ); \
DBG_DC_IF ( level ); \
} while ( 0 )
#define DBGC_PAUSE_IF( level, id ) do { \
DBG_AC_IF ( level, id ); \
DBG_PAUSE_IF ( level ); \
@@ -436,11 +481,15 @@ int __debug_disable;
#define DBG( ... ) DBG_IF ( LOG, ##__VA_ARGS__ )
#define DBG_HDA( ... ) DBG_HDA_IF ( LOG, ##__VA_ARGS__ )
#define DBG_HD( ... ) DBG_HD_IF ( LOG, ##__VA_ARGS__ )
#define DBG_MD5A( ... ) DBG_MD5A_IF ( LOG, ##__VA_ARGS__ )
#define DBG_MD5( ... ) DBG_MD5_IF ( LOG, ##__VA_ARGS__ )
#define DBG_PAUSE( ... ) DBG_PAUSE_IF ( LOG, ##__VA_ARGS__ )
#define DBG_MORE( ... ) DBG_MORE_IF ( LOG, ##__VA_ARGS__ )
#define DBGC( ... ) DBGC_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_HDA( ... ) DBGC_HDA_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_HD( ... ) DBGC_HD_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_MD5A( ... ) DBGC_MD5A_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_MD5( ... ) DBGC_MD5_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_PAUSE( ... ) DBGC_PAUSE_IF ( LOG, ##__VA_ARGS__ )
#define DBGC_MORE( ... ) DBGC_MORE_IF ( LOG, ##__VA_ARGS__ )
@@ -449,11 +498,15 @@ int __debug_disable;
#define DBG2( ... ) DBG_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_HDA( ... ) DBG_HDA_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_HD( ... ) DBG_HD_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_MD5A( ... ) DBG_MD5A_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_MD5( ... ) DBG_MD5_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_PAUSE( ... ) DBG_PAUSE_IF ( EXTRA, ##__VA_ARGS__ )
#define DBG2_MORE( ... ) DBG_MORE_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2( ... ) DBGC_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_HDA( ... ) DBGC_HDA_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_HD( ... ) DBGC_HD_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MD5A( ... ) DBGC_MD5A_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MD5( ... ) DBGC_MD5_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_PAUSE( ... ) DBGC_PAUSE_IF ( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MORE( ... ) DBGC_MORE_IF ( EXTRA, ##__VA_ARGS__ )
@@ -462,11 +515,15 @@ int __debug_disable;
#define DBGP( ... ) DBG_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_HDA( ... ) DBG_HDA_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_HD( ... ) DBG_HD_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_MD5A( ... ) DBG_MD5A_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_MD5( ... ) DBG_MD5_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_PAUSE( ... ) DBG_PAUSE_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGP_MORE( ... ) DBG_MORE_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP( ... ) DBGC_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_HDA( ... ) DBGC_HDA_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_HD( ... ) DBGC_HD_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MD5A( ... ) DBGC_MD5A_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MD5( ... ) DBGC_MD5_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_PAUSE( ... ) DBGC_PAUSE_IF ( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MORE( ... ) DBGC_MORE_IF ( PROFILE, ##__VA_ARGS__ )
@@ -475,11 +532,15 @@ int __debug_disable;
#define DBGIO( ... ) DBG_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_HDA( ... ) DBG_HDA_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_HD( ... ) DBG_HD_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_MD5A( ... ) DBG_MD5A_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_MD5( ... ) DBG_MD5_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_PAUSE( ... ) DBG_PAUSE_IF ( IO, ##__VA_ARGS__ )
#define DBGIO_MORE( ... ) DBG_MORE_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO( ... ) DBGC_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_HDA( ... ) DBGC_HDA_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_HD( ... ) DBGC_HD_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_MD5A( ... ) DBGC_MD5A_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_MD5( ... ) DBGC_MD5_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_PAUSE( ... ) DBGC_PAUSE_IF ( IO, ##__VA_ARGS__ )
#define DBGCIO_MORE( ... ) DBGC_MORE_IF ( IO, ##__VA_ARGS__ )
@@ -537,6 +598,19 @@ int __debug_disable;
/** Declare a function to be always inline */
#define __always_inline __attribute__ (( always_inline ))
/* Force all inline functions to not be instrumented
*
* This is required to cope with what seems to be a long-standing gcc
* bug, in which -finstrument-functions will cause instances of
* inlined functions to be reported as further calls to the
* *containing* function. This makes instrumentation very difficult
* to use.
*
* Work around this problem by adding the no_instrument_function
* attribute to all inlined functions.
*/
#define inline inline __attribute__ (( no_instrument_function ))
/**
* Shared data.
*
+8 -1
View File
@@ -21,10 +21,17 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/parseopt.h>
struct net_device;
struct ifcommon_options {};
extern struct option_descriptor ifcommon_opts[0];
extern int ifcommon_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int ( * payload ) ( struct net_device * ),
const char *verb );
int stop_on_first_success );
#endif /* _IFMGMT_CMD_H */
+2
View File
@@ -14,6 +14,8 @@
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*/
FILE_LICENCE ( GPL2_ONLY );
#ifndef _LINUX_I82365_H
#define _LINUX_I82365_H
+2 -2
View File
@@ -620,8 +620,8 @@ struct dhcphdr {
/** Setting block name used for BootServerDHCP responses */
#define PXEBS_SETTINGS_NAME "pxebs"
extern void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
uint16_t *flags );
extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
uint16_t *flags );
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
struct net_device *netdev, uint8_t msgtype,
const void *options, size_t options_len,
+8
View File
@@ -59,6 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_acpi ( ERRFILE_CORE | 0x00130000 )
#define ERRFILE_null_sanboot ( ERRFILE_CORE | 0x00140000 )
#define ERRFILE_edd ( ERRFILE_CORE | 0x00150000 )
#define ERRFILE_parseopt ( ERRFILE_CORE | 0x00160000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@@ -66,6 +67,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_mca ( ERRFILE_DRIVER | 0x00030000 )
#define ERRFILE_pci ( ERRFILE_DRIVER | 0x00040000 )
#define ERRFILE_linux ( ERRFILE_DRIVER | 0x00050000 )
#define ERRFILE_pcivpd ( ERRFILE_DRIVER | 0x00060000 )
#define ERRFILE_nvs ( ERRFILE_DRIVER | 0x00100000 )
#define ERRFILE_spi ( ERRFILE_DRIVER | 0x00110000 )
@@ -133,6 +135,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_jme ( ERRFILE_DRIVER | 0x005b0000 )
#define ERRFILE_virtio_net ( ERRFILE_DRIVER | 0x005c0000 )
#define ERRFILE_tap ( ERRFILE_DRIVER | 0x005d0000 )
#define ERRFILE_igbvf_main ( ERRFILE_DRIVER | 0x005e0000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
@@ -190,6 +193,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_fcp ( ERRFILE_NET | 0x002d0000 )
#define ERRFILE_fcoe ( ERRFILE_NET | 0x002e0000 )
#define ERRFILE_fcns ( ERRFILE_NET | 0x002f0000 )
#define ERRFILE_vlan ( ERRFILE_NET | 0x00300000 )
#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
@@ -226,6 +230,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_iwmgmt ( ERRFILE_OTHER | 0x00190000 )
#define ERRFILE_linux_smbios ( ERRFILE_OTHER | 0x001a0000 )
#define ERRFILE_lotest ( ERRFILE_OTHER | 0x001b0000 )
#define ERRFILE_config_cmd ( ERRFILE_OTHER | 0x001c0000 )
#define ERRFILE_ifmgmt_cmd ( ERRFILE_OTHER | 0x001d0000 )
#define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 )
#define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 )
/** @} */
+2 -1
View File
@@ -325,7 +325,8 @@ extern int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
extern void fc_port_logout ( struct fc_port *port, int rc );
extern int fc_port_open ( struct interface *transport,
const struct fc_name *node_wwn,
const struct fc_name *port_wwn );
const struct fc_name *port_wwn,
const char *name );
extern struct fc_port * fc_port_find ( const char *name );
/******************************************************************************
+3
View File
@@ -86,4 +86,7 @@ enum fcoe_eof {
FCOE_EOF_A = 0x50, /**< End of Frame Abort */
};
/** FCoE VLAN priority */
#define FCOE_VLAN_PRIORITY 3
#endif /* _IPXE_FCOE_H */
+1
View File
@@ -51,6 +51,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */
#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */
#define DHCP_EB_FEATURE_FCOE 0x25 /**< FCoE protocol */
#define DHCP_EB_FEATURE_VLAN 0x26 /**< VLAN support */
/** @} */
+1
View File
@@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ETH_P_IP 0x0800 /* Internet Protocl Packet */
#define ETH_P_ARP 0x0806 /* Address Resolution Protocol */
#define ETH_P_RARP 0x8035 /* Reverse Address resolution Protocol */
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
#define ETH_P_IPV6 0x86DD /* IPv6 over blueblook */
#define ETH_P_SLOW 0x8809 /* Ethernet slow protocols */
#define ETH_P_EAPOL 0x888E /* 802.1X EAP over LANs */
+4
View File
@@ -89,6 +89,10 @@ struct ib_address_vector {
unsigned int gid_present;
/** GID, if present */
union ib_gid gid;
/** VLAN is present */
unsigned int vlan_present;
/** VLAN, if present */
unsigned int vlan;
};
/** An Infiniband Work Queue */
+54 -9
View File
@@ -36,15 +36,26 @@ struct device;
/** Maximum length of a link-layer header
*
* The longest currently-supported link-layer header is for 802.11: a
* 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header. (The
* IPoIB link-layer pseudo-header doesn't actually include link-layer
* addresses; see ipoib.c for details).
* 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header, plus a
* possible 4-byte VLAN header. (The IPoIB link-layer pseudo-header
* doesn't actually include link-layer addresses; see ipoib.c for
* details.)
*/
#define MAX_LL_HEADER_LEN 32
#define MAX_LL_HEADER_LEN 36
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4
/** Maximum length of a network-layer header
*
* The longest currently-supported network-layer header is for IPv6 at
* 40 bytes.
*/
#define MAX_NET_HEADER_LEN 40
/** Maximum combined length of a link-layer and network-layer header */
#define MAX_LL_NET_HEADER_LEN ( MAX_LL_HEADER_LEN + MAX_NET_HEADER_LEN )
/**
* A network-layer protocol
*
@@ -268,7 +279,7 @@ struct net_device {
/** List of open network devices */
struct list_head open_list;
/** Name of this network device */
char name[8];
char name[12];
/** Underlying hardware device */
struct device *dev;
@@ -333,6 +344,9 @@ struct net_device {
/** Network device interrupts are enabled */
#define NETDEV_IRQ_ENABLED 0x0002
/** Network device receive queue processing is frozen */
#define NETDEV_RX_FROZEN 0x0004
/** Link-layer protocol table */
#define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" )
@@ -475,8 +489,7 @@ netdev_settings ( struct net_device *netdev ) {
*/
static inline __attribute__ (( always_inline )) void
netdev_settings_init ( struct net_device *netdev ) {
generic_settings_init ( &netdev->settings,
&netdev->refcnt, netdev->name );
generic_settings_init ( &netdev->settings, &netdev->refcnt );
netdev->settings.settings.op = &netdev_settings_operations;
}
@@ -495,7 +508,7 @@ netdev_link_ok ( struct net_device *netdev ) {
* Check whether or not network device is open
*
* @v netdev Network device
* @v is_open Network device is open
* @ret is_open Network device is open
*/
static inline __attribute__ (( always_inline )) int
netdev_is_open ( struct net_device *netdev ) {
@@ -506,13 +519,24 @@ netdev_is_open ( struct net_device *netdev ) {
* Check whether or not network device interrupts are currently enabled
*
* @v netdev Network device
* @v irq_enabled Network device interrupts are enabled
* @ret irq_enabled Network device interrupts are enabled
*/
static inline __attribute__ (( always_inline )) int
netdev_irq_enabled ( struct net_device *netdev ) {
return ( netdev->state & NETDEV_IRQ_ENABLED );
}
/**
* Check whether or not network device receive queue processing is frozen
*
* @v netdev Network device
* @ret rx_frozen Network device receive queue processing is frozen
*/
static inline __attribute__ (( always_inline )) int
netdev_rx_frozen ( struct net_device *netdev ) {
return ( netdev->state & NETDEV_RX_FROZEN );
}
extern void netdev_link_err ( struct net_device *netdev, int rc );
extern void netdev_link_down ( struct net_device *netdev );
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
@@ -540,6 +564,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
uint16_t net_proto, const void *ll_dest,
const void *ll_source );
extern void net_poll ( void );
/**
* Complete network transmission
@@ -575,4 +600,24 @@ netdev_link_up ( struct net_device *netdev ) {
netdev_link_err ( netdev, 0 );
}
/**
* Freeze network device receive queue processing
*
* @v netdev Network device
*/
static inline __attribute__ (( always_inline )) void
netdev_rx_freeze ( struct net_device *netdev ) {
netdev->state |= NETDEV_RX_FROZEN;
}
/**
* Unfreeze network device receive queue processing
*
* @v netdev Network device
*/
static inline __attribute__ (( always_inline )) void
netdev_rx_unfreeze ( struct net_device *netdev ) {
netdev->state &= ~NETDEV_RX_FROZEN;
}
#endif /* _IPXE_NETDEVICE_H */
+33
View File
@@ -0,0 +1,33 @@
#ifndef _IPXE_NVSVPD_H
#define _IPXE_NVSVPD_H
/**
* @file
*
* Non-Volatile Storage using Vital Product Data
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/nvs.h>
#include <ipxe/pcivpd.h>
/** An NVS VPD device */
struct nvs_vpd_device {
/** NVS device */
struct nvs_device nvs;
/** PCI VPD device */
struct pci_vpd vpd;
/** Starting address
*
* This address is added to the NVS address to form the VPD
* address.
*/
unsigned int address;
};
extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
unsigned int field );
#endif /* IPXE_NVSVPD_H */
+127
View File
@@ -0,0 +1,127 @@
#ifndef _IPXE_PARSEOPT_H
#define _IPXE_PARSEOPT_H
/** @file
*
* Command line option parsing
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stddef.h>
struct net_device;
struct image;
/** A command-line option descriptor */
struct option_descriptor {
/** Long option name, if any */
const char *longopt;
/** Short option name */
char shortopt;
/** Argument requirement (as for @c struct @c option) */
uint8_t has_arg;
/** Offset of field within options structure */
uint16_t offset;
/** Parse option
*
* @v text Option text
* @v value Option value to fill in
* @ret rc Return status code
*/
int ( * parse ) ( const char *text, void *value );
};
/**
* Construct option parser
*
* @v _struct Options structure type
* @v _field Field within options structure
* @v _parse Field type-specific option parser
* @ret _parse Generic option parser
*/
#define OPTION_PARSER( _struct, _field, _parse ) \
( ( int ( * ) ( const char *text, void *value ) ) \
( ( ( ( typeof ( _parse ) * ) NULL ) == \
( ( int ( * ) ( const char *text, \
typeof ( ( ( _struct * ) NULL )->_field ) * ) ) \
NULL ) ) ? _parse : _parse ) )
/**
* Construct option descriptor
*
* @v _longopt Long option name, if any
* @v _shortopt Short option name, if any
* @v _has_arg Argument requirement
* @v _struct Options structure type
* @v _field Field within options structure
* @v _parse Field type-specific option parser
* @ret _option Option descriptor
*/
#define OPTION_DESC( _longopt, _shortopt, _has_arg, _struct, _field, _parse ) \
{ \
.longopt = _longopt, \
.shortopt = _shortopt, \
.has_arg = _has_arg, \
.offset = offsetof ( _struct, _field ), \
.parse = OPTION_PARSER ( _struct, _field, _parse ), \
}
/** A command descriptor */
struct command_descriptor {
/** Option descriptors */
struct option_descriptor *options;
/** Number of option descriptors */
uint8_t num_options;
/** Length of option structure */
uint8_t len;
/** Minimum number of non-option arguments */
uint8_t min_args;
/** Maximum number of non-option arguments */
uint8_t max_args;
/** Command usage and description
*
* This excludes the literal "Usage:" and the command name,
* which will be prepended automatically.
*/
const char *usage_description;
};
/** No maximum number of arguments */
#define MAX_ARGUMENTS 0xff
/**
* Construct command descriptor
*
* @v _struct Options structure type
* @v _options Option descriptor array
* @v _check_args Remaining argument checker
* @v _usage Command usage
* @v _description Command description
* @ret _command Command descriptor
*/
#define COMMAND_DESC( _struct, _options, _min_args, _max_args, _usage, \
_description ) \
{ \
.options = ( ( ( ( typeof ( _options[0] ) * ) NULL ) == \
( ( struct option_descriptor * ) NULL ) ) ? \
_options : _options ), \
.num_options = ( sizeof ( _options ) / \
sizeof ( _options[0] ) ), \
.len = sizeof ( _struct ), \
.min_args = _min_args, \
.max_args = _max_args, \
.usage_description = _usage "\n\n" _description, \
}
extern int parse_string ( const char *text, const char **value );
extern int parse_integer ( const char *text, unsigned int *value );
extern int parse_netdev ( const char *text, struct net_device **netdev );
extern int parse_image ( const char *text, struct image **image );
extern void print_usage ( struct command_descriptor *cmd, char **argv );
extern int parse_options ( int argc, char **argv,
struct command_descriptor *cmd, void *opts );
#endif /* _IPXE_PARSEOPT_H */
+7
View File
@@ -374,6 +374,13 @@ struct pci_driver {
#define PCI_ROM( _vendor, _device, _name, _description, _data ) \
PCI_ID( _vendor, _device, _name, _description, _data )
/** PCI device debug message format */
#define PCI_FMT "PCI %02x:%02x.%x"
/** PCI device debug message arguments */
#define PCI_ARGS( pci ) \
(pci)->bus, PCI_SLOT ( (pci)->devfn ), PCI_FUNC ( (pci)->devfn )
extern void adjust_pci_device ( struct pci_device *pci );
extern unsigned long pci_bar_start ( struct pci_device *pci,
unsigned int reg );
+165
View File
@@ -0,0 +1,165 @@
#ifndef _IPXE_PCIVPD_H
#define _IPXE_PCIVPD_H
/**
* @file
*
* PCI Vital Product Data
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/isapnp.h>
#include <ipxe/pci.h>
/** PCI VPD address register */
#define PCI_VPD_ADDRESS 0x02
/** PCI VPD write flag */
#define PCI_VPD_FLAG 0x8000
/** PCI VPD data register */
#define PCI_VPD_DATA 0x04
/** A PCI VPD field */
struct pci_vpd_field {
/** Keyword */
uint16_t keyword;
/** Length */
uint8_t len;
} __attribute__ (( packed ));
/** Construct PCI VPD field descriptor
*
* @v tag ISAPnP tag
* @v keyword1 First character of keyword
* @v keyword2 Second character of keyword
* @ret field VPD field descriptor
*/
#define PCI_VPD_FIELD( tag, keyword1, keyword2 ) \
( ( (tag) << 16 ) | ( (keyword2) << 8 ) | ( (keyword1) << 0 ) )
/** Construct PCI VPD whole-tag field descriptor
*
* @v tag ISAPnP tag
* @ret field VPD field descriptor
*/
#define PCI_VPD_WHOLE_TAG_FIELD( tag ) PCI_VPD_FIELD ( (tag), '\0', '\0' )
/** Extract PCI VPD ISAPnP tag
*
* @v field VPD field descriptor
* @ret tag ISAPnP tag
*/
#define PCI_VPD_TAG( field ) ( (field) >> 16 )
/** Extract PCI VPD keyword
*
* @v field VPD field descriptor
* @ret keyword Keyword
*/
#define PCI_VPD_KEYWORD( field ) ( cpu_to_le16 ( (field) & 0xffff ) )
/** PCI VPD field debug message format */
#define PCI_VPD_FIELD_FMT "%c%c"
/** PCI VPD field debug message arguments */
#define PCI_VPD_FIELD_ARGS( field ) \
( (field) >> 0 ), ( (field) >> 8 )
/** PCI VPD Read-Only field tag */
#define PCI_VPD_TAG_RO 0x90
/** PCI VPD Read-Write field tag */
#define PCI_VPD_TAG_RW 0x91
/** PCI VPD Card Name field descriptor */
#define PCI_VPD_FIELD_NAME PCI_VPD_WHOLE_TAG_FIELD ( ISAPNP_TAG_ANSISTR )
/** PCI VPD Part Number field descriptor */
#define PCI_VPD_FIELD_PN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'N' )
/** PCI VPD Engineering Change Level field descriptor */
#define PCI_VPD_FIELD_EC PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'E', 'C' )
/** PCI VPD Fabric Geography field descriptor */
#define PCI_VPD_FIELD_FG PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'F', 'G' )
/** PCI VPD Location field descriptor */
#define PCI_VPD_FIELD_LC PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'L', 'C' )
/** PCI VPD Manufacturer ID field descriptor */
#define PCI_VPD_FIELD_MN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'M', 'N' )
/** PCI VPD PCI Geography field descriptor */
#define PCI_VPD_FIELD_PG PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'G' )
/** PCI VPD Serial Number field descriptor */
#define PCI_VPD_FIELD_SN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'S', 'N' )
/** PCI VPD Extended Capability field descriptor */
#define PCI_VPD_FIELD_CP PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'C', 'P' )
/** PCI VPD Checksum and Reserved field descriptor */
#define PCI_VPD_FIELD_RV PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'R', 'V' )
/** PCI VPD Asset Tag field descriptor */
#define PCI_VPD_FIELD_YA PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'Y', 'A' )
/** PCI VPD Remaining Read/Write Area field descriptor */
#define PCI_VPD_FIELD_RW PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'R', 'W' )
/** Maximum wait for PCI VPD (in ms) */
#define PCI_VPD_MAX_WAIT_MS 100
/** PCI VPD cache */
struct pci_vpd_cache {
/** Address */
int address;
/** Data */
uint32_t data;
};
/** PCI VPD */
struct pci_vpd {
/** PCI device */
struct pci_device *pci;
/** VPD capability offset */
int cap;
/** Read cache */
struct pci_vpd_cache cache;
};
/**
* Check if PCI VPD read cache is valid
*
* @v vpd PCI VPD
* @ret is_valid Read cache is valid
*/
static inline __attribute__ (( always_inline )) int
pci_vpd_cache_is_valid ( struct pci_vpd *vpd ) {
return ( vpd->cache.address >= 0 );
}
/**
* Invalidate PCI VPD read cache
*
* @v vpd PCI VPD
*/
static inline __attribute__ (( always_inline )) void
pci_vpd_invalidate_cache ( struct pci_vpd *vpd ) {
vpd->cache.address = -1;
}
extern int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci );
extern int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address,
void *buf, size_t len );
extern int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address,
const void *buf, size_t len );
extern int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
unsigned int *address, size_t *len );
#endif /* _IPXE_PCIVPD_H */
+7 -8
View File
@@ -178,7 +178,7 @@ extern int generic_settings_fetch ( struct settings *settings,
extern void generic_settings_clear ( struct settings *settings );
extern int register_settings ( struct settings *settings,
struct settings *parent );
struct settings *parent, const char *name );
extern void unregister_settings ( struct settings *settings );
extern int store_setting ( struct settings *settings, struct setting *setting,
@@ -193,6 +193,10 @@ extern int fetch_string_setting ( struct settings *settings,
extern int fetch_string_setting_copy ( struct settings *settings,
struct setting *setting,
char **data );
extern int fetch_ipv4_array_setting ( struct settings *settings,
struct setting *setting,
struct in_addr *inp,
unsigned int count );
extern int fetch_ipv4_setting ( struct settings *settings,
struct setting *setting, struct in_addr *inp );
extern int fetch_int_setting ( struct settings *settings,
@@ -252,19 +256,16 @@ extern struct setting user_class_setting __setting;
* @v settings Settings block
* @v op Settings block operations
* @v refcnt Containing object reference counter, or NULL
* @v name Settings block name
* @v tag_magic Tag magic
*/
static inline void settings_init ( struct settings *settings,
struct settings_operations *op,
struct refcnt *refcnt,
const char *name,
unsigned int tag_magic ) {
INIT_LIST_HEAD ( &settings->siblings );
INIT_LIST_HEAD ( &settings->children );
settings->op = op;
settings->refcnt = refcnt;
settings->name = name;
settings->tag_magic = tag_magic;
}
@@ -273,13 +274,11 @@ static inline void settings_init ( struct settings *settings,
*
* @v generics Generic settings block
* @v refcnt Containing object reference counter, or NULL
* @v name Settings block name
*/
static inline void generic_settings_init ( struct generic_settings *generics,
struct refcnt *refcnt,
const char *name ) {
struct refcnt *refcnt ) {
settings_init ( &generics->settings, &generic_settings_operations,
refcnt, name, 0 );
refcnt, 0 );
INIT_LIST_HEAD ( &generics->list );
}
+23 -1
View File
@@ -9,6 +9,28 @@
FILE_LICENCE ( GPL2_OR_LATER );
extern void shell ( void );
/** Shell stop states */
enum shell_stop_state {
/** Continue processing */
SHELL_CONTINUE = 0,
/**
* Stop processing current command line
*
* This is the stop state entered by commands that change the flow
* of execution, such as "goto".
*/
SHELL_STOP_COMMAND = 1,
/**
* Stop processing commands
*
* This is the stop state entered by commands that terminate
* the flow of execution, such as "exit".
*/
SHELL_STOP_COMMAND_SEQUENCE = 2,
};
extern void shell_stop ( int stop );
extern int shell_stopped ( int stop );
extern int shell ( void );
#endif /* _IPXE_SHELL_H */
-5
View File
@@ -257,11 +257,6 @@ struct tcp_options {
/** Smallest port number on which a TCP connection can listen */
#define TCP_MIN_PORT 1
/* Some IOB constants */
#define MAX_HDR_LEN 100
#define MAX_IOB_LEN 1500
#define MIN_IOB_LEN MAX_HDR_LEN + 100 /* To account for padding by LL */
/**
* Maxmimum advertised TCP window size
*
-4
View File
@@ -23,10 +23,6 @@ struct sockaddr;
* UDP constants
*/
#define UDP_MAX_HLEN 72
#define UDP_MAX_TXIOB ETH_MAX_MTU
#define UDP_MIN_TXIOB ETH_ZLEN
/**
* A UDP header
*/
+69
View File
@@ -0,0 +1,69 @@
#ifndef _IPXE_VLAN_H
#define _IPXE_VLAN_H
/**
* @file
*
* Virtual LANs
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** A VLAN header */
struct vlan_header {
/** Tag control information */
uint16_t tci;
/** Encapsulated protocol */
uint16_t net_proto;
} __attribute__ (( packed ));
/**
* Extract VLAN tag from tag control information
*
* @v tci Tag control information
* @ret tag VLAN tag
*/
#define VLAN_TAG( tci ) ( (tci) & 0x0fff )
/**
* Extract VLAN priority from tag control information
*
* @v tci Tag control information
* @ret priority Priority
*/
#define VLAN_PRIORITY( tci ) ( (tci) >> 13 )
/**
* Construct VLAN tag control information
*
* @v tag VLAN tag
* @v priority Priority
* @ret tci Tag control information
*/
#define VLAN_TCI( tag, priority ) ( ( (priority) << 13 ) | (tag) )
/**
* Check VLAN tag is valid
*
* @v tag VLAN tag
* @ret is_valid VLAN tag is valid
*/
#define VLAN_TAG_IS_VALID( tag ) ( (tag) < 0xfff )
/**
* Check VLAN priority is valid
*
* @v priority VLAN priority
* @ret is_valid VLAN priority is valid
*/
#define VLAN_PRIORITY_IS_VALID( priority ) ( (priority) <= 7 )
extern struct net_device * vlan_find ( struct net_device *trunk,
unsigned int tag );
extern int vlan_can_be_trunk ( struct net_device *trunk );
extern int vlan_create ( struct net_device *trunk, unsigned int tag,
unsigned int priority );
extern int vlan_destroy ( struct net_device *netdev );
#endif /* _IPXE_VLAN_H */
+4
View File
@@ -10,7 +10,11 @@ FILE_LICENCE ( GPL2_ONLY );
#define NULL ((void *)0)
#undef offsetof
#if ( defined ( __GNUC__ ) && ( __GNUC__ > 3 ) )
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#undef container_of
#define container_of(ptr, type, member) ({ \
+2 -1
View File
@@ -14,7 +14,8 @@ struct net_device;
extern int shutdown_exit_flags;
extern void autoboot ( void );
extern int netboot ( struct net_device *netdev );
extern int autoboot ( void );
extern int boot_next_server_and_filename ( struct in_addr next_server,
const char *filename );
extern int boot_root_path ( const char *root_path );
+4 -1
View File
@@ -530,6 +530,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
container_of ( snp, struct efi_snp_device, snp );
struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
struct io_buffer *iobuf;
size_t ll_headroom;
int rc;
EFI_STATUS efirc;
@@ -582,13 +583,15 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
}
/* Allocate buffer */
iobuf = alloc_iob ( len );
ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len );
iobuf = alloc_iob ( ll_headroom + len );
if ( ! iobuf ) {
DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
"buffer\n", snpdev, ( ( unsigned long ) len ) );
efirc = EFI_DEVICE_ERROR;
goto err_alloc_iob;
}
iob_reserve ( iobuf, ll_headroom );
memcpy ( iob_put ( iobuf, len ), data, len );
/* Create link-layer header, if specified */
+2 -2
View File
@@ -125,7 +125,6 @@ static struct settings_operations smbios_settings_operations = {
/** SMBIOS settings */
static struct settings smbios_settings = {
.refcnt = NULL,
.name = "smbios",
.tag_magic = SMBIOS_EMPTY_TAG,
.siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
.children = LIST_HEAD_INIT ( smbios_settings.children ),
@@ -136,7 +135,8 @@ static struct settings smbios_settings = {
static void smbios_init ( void ) {
int rc;
if ( ( rc = register_settings ( &smbios_settings, NULL ) ) != 0 ) {
if ( ( rc = register_settings ( &smbios_settings, NULL,
"smbios" ) ) != 0 ) {
DBG ( "SMBIOS could not register settings: %s\n",
strerror ( rc ) );
return;
+2 -1
View File
@@ -66,7 +66,8 @@ void store_cached_dhcpack ( userptr_t data, size_t len ) {
* device, which is usually what we want.
*/
parent = netdev_settings ( last_opened_netdev() );
if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 )
if ( ( rc = register_settings ( &dhcppkt->settings, parent,
DHCP_SETTINGS_NAME ) ) != 0 )
DBG ( "DHCP could not register cached settings: %s\n",
strerror ( rc ) );
+1 -2
View File
@@ -279,6 +279,5 @@ void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.len );
settings_init ( &dhcppkt->settings,
&dhcppkt_settings_operations, &dhcppkt->refcnt,
DHCP_SETTINGS_NAME, 0 );
&dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
}
+12 -12
View File
@@ -111,25 +111,25 @@ static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
struct eth_slow_lacp *lacp = &eth_slow->lacp;
DBGC ( netdev,
"SLOW %p %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
netdev, label, ntohs ( lacp->actor.system_priority ),
"SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
netdev->name, label, ntohs ( lacp->actor.system_priority ),
eth_ntoa ( lacp->actor.system ),
ntohs ( lacp->actor.key ),
ntohs ( lacp->actor.port_priority ),
ntohs ( lacp->actor.port ),
eth_slow_lacp_state_name ( lacp->actor.state ) );
DBGC ( netdev,
"SLOW %p %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
netdev, label, ntohs ( lacp->partner.system_priority ),
"SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
netdev->name, label, ntohs ( lacp->partner.system_priority ),
eth_ntoa ( lacp->partner.system ),
ntohs ( lacp->partner.key ),
ntohs ( lacp->partner.port_priority ),
ntohs ( lacp->partner.port ),
eth_slow_lacp_state_name ( lacp->partner.state ) );
DBGC ( netdev, "SLOW %p %s LACP collector %04x (%d us)\n",
netdev, label, ntohs ( lacp->collector.max_delay ),
DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n",
netdev->name, label, ntohs ( lacp->collector.max_delay ),
( ntohs ( lacp->collector.max_delay ) * 10 ) );
DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
}
/**
@@ -191,13 +191,13 @@ static void eth_slow_marker_dump ( struct io_buffer *iobuf,
union eth_slow_packet *eth_slow = iobuf->data;
struct eth_slow_marker *marker = &eth_slow->marker;
DBGC ( netdev, "SLOW %p %s marker %s port %04x system %s xact %08x\n",
netdev, label,
DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
netdev->name, label,
eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
ntohs ( marker->marker.port ),
eth_ntoa ( marker->marker.system ),
ntohl ( marker->marker.xact ) );
DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
}
/**
@@ -255,8 +255,8 @@ static int eth_slow_rx ( struct io_buffer *iobuf,
case ETH_SLOW_SUBTYPE_MARKER:
return eth_slow_marker_rx ( iobuf, netdev );
default:
DBGC ( netdev, "SLOW %p RX unknown subtype %02x\n",
netdev, eth_slow->header.subtype );
DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n",
netdev->name, eth_slow->header.subtype );
free_iob ( iobuf );
return -EINVAL;
}
+3 -5
View File
@@ -1178,11 +1178,11 @@ static struct interface_descriptor fc_port_ns_plogi_desc =
* @v transport Transport interface
* @v node Fibre Channel node name
* @v port Fibre Channel port name
* @v name Symbolic port name
* @ret rc Return status code
*/
int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
const struct fc_name *port_wwn ) {
static unsigned int portindex = 0;
const struct fc_name *port_wwn, const char *name ) {
struct fc_port *port;
/* Allocate and initialise structure */
@@ -1198,9 +1198,7 @@ int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
INIT_LIST_HEAD ( &port->xchgs );
memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
/* Create device name */
snprintf ( port->name, sizeof ( port->name ), "fc%d", portindex++ );
snprintf ( port->name, sizeof ( port->name ), "%s", name );
DBGC ( port, "FCPORT %s opened as %s",
port->name, fc_ntoa ( &port->node_wwn ) );
+176 -18
View File
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xfer.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/vlan.h>
#include <ipxe/features.h>
#include <ipxe/errortab.h>
#include <ipxe/device.h>
@@ -103,6 +104,10 @@ enum fcoe_flags {
FCOE_HAVE_FIP_FCF = 0x0004,
/** FCoE forwarder supports server-provided MAC addresses */
FCOE_FCF_ALLOWS_SPMA = 0x0008,
/** An alternative VLAN has been found */
FCOE_VLAN_FOUND = 0x0010,
/** VLAN discovery has timed out */
FCOE_VLAN_TIMED_OUT = 0x0020,
};
struct net_protocol fcoe_protocol __net_protocol;
@@ -124,6 +129,15 @@ static uint8_t all_fcf_macs[ETH_ALEN] =
static uint8_t default_fcf_mac[ETH_ALEN] =
{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
/** Maximum number of VLAN requests before giving up on VLAN discovery */
#define FCOE_MAX_VLAN_REQUESTS 2
/** Delay between retrying VLAN requests */
#define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
/** Delay between retrying polling VLAN requests */
#define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
/** Maximum number of FIP solicitations before giving up on FIP */
#define FCOE_MAX_FIP_SOLICITATIONS 2
@@ -166,6 +180,9 @@ static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
*/
static void fcoe_reset ( struct fcoe_port *fcoe ) {
/* Detach FC port, if any */
intf_restart ( &fcoe->transport, -ECANCELED );
/* Reset any FIP state */
stop_timer ( &fcoe->timer );
fcoe->timeouts = 0;
@@ -182,8 +199,9 @@ static void fcoe_reset ( struct fcoe_port *fcoe ) {
netdev_link_ok ( fcoe->netdev ) ) {
fcoe->flags |= FCOE_HAVE_NETWORK;
start_timer_nodelay ( &fcoe->timer );
DBGC ( fcoe, "FCoE %s starting FIP solicitation\n",
fcoe->netdev->name );
DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
( vlan_can_be_trunk ( fcoe->netdev ) ?
"VLAN discovery" : "FIP solicitation" ) );
}
/* Send notification of window change */
@@ -515,7 +533,9 @@ static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
/* Handle descriptors that we understand */
if ( ( desc_type > FIP_RESERVED ) &&
( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
descs->desc[desc_type] = desc;
/* Use only the first instance of a descriptor */
if ( descs->desc[desc_type] == NULL )
descs->desc[desc_type] = desc;
continue;
}
@@ -533,6 +553,100 @@ static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
return 0;
}
/**
* Send FIP VLAN request
*
* @v fcoe FCoE port
* @ret rc Return status code
*/
static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
struct io_buffer *iobuf;
struct {
struct fip_header hdr;
struct fip_mac_address mac_address;
} __attribute__ (( packed )) *request;
int rc;
/* Allocate I/O buffer */
iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
if ( ! iobuf )
return -ENOMEM;
iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
/* Construct VLAN request */
request = iob_put ( iobuf, sizeof ( *request ) );
memset ( request, 0, sizeof ( *request ) );
request->hdr.version = FIP_VERSION;
request->hdr.code = htons ( FIP_CODE_VLAN );
request->hdr.subcode = FIP_VLAN_REQUEST;
request->hdr.len = htons ( ( sizeof ( *request ) -
sizeof ( request->hdr ) ) / 4 );
request->mac_address.type = FIP_MAC_ADDRESS;
request->mac_address.len =
( sizeof ( request->mac_address ) / 4 );
memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
sizeof ( request->mac_address.mac ) );
/* Send VLAN request */
if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
&fip_protocol, all_fcf_macs,
fcoe->netdev->ll_addr ) ) != 0 ) {
DBGC ( fcoe, "FCoE %s could not send VLAN request: "
"%s\n", fcoe->netdev->name, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Handle received FIP VLAN notification
*
* @v fcoe FCoE port
* @v descs Descriptor list
* @v flags Flags
* @ret rc Return status code
*/
static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
struct fip_descriptors *descs,
unsigned int flags __unused ) {
struct fip_mac_address *mac_address = fip_mac_address ( descs );
struct fip_vlan *vlan = fip_vlan ( descs );
unsigned int tag;
int rc;
/* Sanity checks */
if ( ! mac_address ) {
DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
"address\n", fcoe->netdev->name );
return -EINVAL;
}
if ( ! vlan ) {
DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
"tag\n", fcoe->netdev->name );
return -EINVAL;
}
/* Create VLAN */
tag = ntohs ( vlan->vlan );
DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
if ( ( rc = vlan_create ( fcoe->netdev, tag,
FCOE_VLAN_PRIORITY ) ) != 0 ) {
DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
fcoe->netdev->name, tag, strerror ( rc ) );
return rc;
}
/* Record that a VLAN was found. This FCoE port will play no
* further active role; the real FCoE traffic will use the
* port automatically created for the new VLAN device.
*/
fcoe->flags |= FCOE_VLAN_FOUND;
return 0;
}
/**
* Send FIP discovery solicitation
*
@@ -646,14 +760,12 @@ static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
fcoe->flags |= FCOE_FCF_ALLOWS_SPMA;
memcpy ( fcoe->fcf_mac, mac_address->mac,
sizeof ( fcoe->fcf_mac ) );
DBGC ( fcoe, "FCoE %s selected FCF %s (priority %d, ",
DBGC ( fcoe, "FCoE %s selected FCF %s (pri %d",
fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
fcoe->priority );
if ( fcoe->keepalive ) {
DBGC ( fcoe, "keepalive %dms",
DBGC ( fcoe, ", FKA ADV %dms",
fcoe->keepalive );
} else {
DBGC ( fcoe, "no keepalive" );
}
DBGC ( fcoe, ", %cPMA)\n",
( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
@@ -797,6 +909,8 @@ struct fip_handler {
/** FIP handlers */
static struct fip_handler fip_handlers[] = {
{ FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
fcoe_fip_rx_vlan },
{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
fcoe_fip_rx_advertisement },
{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
@@ -884,6 +998,7 @@ static int fcoe_fip_rx ( struct io_buffer *iobuf,
static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
struct fcoe_port *fcoe =
container_of ( timer, struct fcoe_port, timer );
int rc;
/* Sanity check */
assert ( fcoe->flags & FCOE_HAVE_NETWORK );
@@ -891,20 +1006,65 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
/* Increment the timeout counter */
fcoe->timeouts++;
if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
if ( vlan_can_be_trunk ( fcoe->netdev ) &
! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
/* If we have already found a VLAN, send infrequent
* VLAN requests, in case VLAN information changes.
*/
if ( fcoe->flags & FCOE_VLAN_FOUND ) {
fcoe->flags &= ~FCOE_VLAN_FOUND;
fcoe->timeouts = 0;
start_timer_fixed ( &fcoe->timer,
FCOE_VLAN_POLL_DELAY );
fcoe_fip_tx_vlan ( fcoe );
return;
}
/* If we have not yet found a VLAN, and we have not
* yet timed out and given up on finding one, then
* send a VLAN request and wait.
*/
if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
start_timer_fixed ( &fcoe->timer,
FCOE_VLAN_RETRY_DELAY );
fcoe_fip_tx_vlan ( fcoe );
return;
}
/* We have timed out waiting for a VLAN; proceed to
* FIP discovery.
*/
fcoe->flags |= FCOE_VLAN_TIMED_OUT;
fcoe->timeouts = 0;
DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
fcoe->netdev->name );
start_timer_nodelay ( &fcoe->timer );
} else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
/* If we have not yet found a FIP-capable forwarder,
* and we have not yet timed out and given up on
* finding one, then send a FIP solicitation and wait.
*/
start_timer_fixed ( &fcoe->timer, FCOE_FIP_RETRY_DELAY );
if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
start_timer_fixed ( &fcoe->timer,
FCOE_FIP_RETRY_DELAY );
fcoe_fip_tx_solicitation ( fcoe );
return;
}
/* Attach Fibre Channel port */
if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
&fcoe->port_wwn.fc,
fcoe->netdev->name ) ) != 0 ) {
DBGC ( fcoe, "FCoE %s could not create FC port: %s\n",
fcoe->netdev->name, strerror ( rc ) );
/* We will try again on the next timer expiry */
return;
}
stop_timer ( &fcoe->timer );
/* Either we have found a FIP-capable forwarder, or we
* have timed out and will fall back to pre-FIP mode.
*/
@@ -979,16 +1139,10 @@ static int fcoe_probe ( struct net_device *netdev ) {
fc_ntoa ( &fcoe->node_wwn.fc ) );
DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
/* Attach Fibre Channel port */
if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
&fcoe->port_wwn.fc ) ) != 0 )
goto err_fc_create;
/* Transfer reference to port list */
list_add ( &fcoe->list, &fcoe_ports );
return 0;
err_fc_create:
netdev_put ( fcoe->netdev );
err_zalloc:
err_non_ethernet:
@@ -1010,8 +1164,12 @@ static void fcoe_notify ( struct net_device *netdev ) {
return;
}
/* Reset the FCoE link */
fcoe_reset ( fcoe );
/* Reset the FCoE link if necessary */
if ( ! ( netdev_is_open ( netdev ) &&
netdev_link_ok ( netdev ) &&
( fcoe->flags & FCOE_HAVE_NETWORK ) ) ) {
fcoe_reset ( fcoe );
}
}
/**
+55 -36
View File
@@ -79,10 +79,10 @@ void netdev_link_err ( struct net_device *netdev, int rc ) {
/* Record link state */
netdev->link_rc = rc;
if ( netdev->link_rc == 0 ) {
DBGC ( netdev, "NETDEV %p link is up\n", netdev );
DBGC ( netdev, "NETDEV %s link is up\n", netdev->name );
} else {
DBGC ( netdev, "NETDEV %p link is down: %s\n",
netdev, strerror ( netdev->link_rc ) );
DBGC ( netdev, "NETDEV %s link is down: %s\n",
netdev->name, strerror ( netdev->link_rc ) );
}
/* Notify drivers of link state change */
@@ -157,8 +157,8 @@ static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
int rc;
DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n",
netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
DBGC ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n",
netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
/* Enqueue packet */
list_add_tail ( &iobuf->list, &netdev->tx_queue );
@@ -202,11 +202,11 @@ void netdev_tx_complete_err ( struct net_device *netdev,
/* Update statistics counter */
netdev_record_stat ( &netdev->tx_stats, rc );
if ( rc == 0 ) {
DBGC ( netdev, "NETDEV %p transmission %p complete\n",
netdev, iobuf );
DBGC ( netdev, "NETDEV %s transmission %p complete\n",
netdev->name, iobuf );
} else {
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
netdev, iobuf, strerror ( rc ) );
DBGC ( netdev, "NETDEV %s transmission %p failed: %s\n",
netdev->name, iobuf, strerror ( rc ) );
}
/* Catch data corruption as early as possible */
@@ -259,8 +259,8 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
*/
void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
DBGC ( netdev, "NETDEV %s received %p (%p+%zx)\n",
netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
/* Discard packet (for test purposes) if applicable */
if ( ( NETDEV_DISCARD_RATE > 0 ) &&
@@ -291,8 +291,8 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
void netdev_rx_err ( struct net_device *netdev,
struct io_buffer *iobuf, int rc ) {
DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
netdev, iobuf, strerror ( rc ) );
DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n",
netdev->name, iobuf, strerror ( rc ) );
/* Discard packet */
free_iob ( iobuf );
@@ -405,8 +405,10 @@ int register_netdev ( struct net_device *netdev ) {
int rc;
/* Create device name */
snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
ifindex++ );
if ( netdev->name[0] == '\0' ) {
snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
ifindex++ );
}
/* Set initial link-layer address */
netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
@@ -414,23 +416,24 @@ int register_netdev ( struct net_device *netdev ) {
/* Add to device list */
netdev_get ( netdev );
list_add_tail ( &netdev->list, &net_devices );
DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
netdev, netdev->name, netdev->dev->name,
DBGC ( netdev, "NETDEV %s registered (phys %s hwaddr %s)\n",
netdev->name, netdev->dev->name,
netdev_addr ( netdev ) );
/* Register per-netdev configuration settings */
if ( ( rc = register_settings ( netdev_settings ( netdev ),
NULL ) ) != 0 ) {
DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
netdev, strerror ( rc ) );
NULL, netdev->name ) ) != 0 ) {
DBGC ( netdev, "NETDEV %s could not register settings: %s\n",
netdev->name, strerror ( rc ) );
goto err_register_settings;
}
/* Probe device */
for_each_table_entry ( driver, NET_DRIVERS ) {
if ( ( rc = driver->probe ( netdev ) ) != 0 ) {
DBGC ( netdev, "NETDEV %p could not add %s device: "
"%s\n", netdev, driver->name, strerror ( rc ) );
DBGC ( netdev, "NETDEV %s could not add %s device: "
"%s\n", netdev->name, driver->name,
strerror ( rc ) );
goto err_probe;
}
}
@@ -458,15 +461,15 @@ int netdev_open ( struct net_device *netdev ) {
if ( netdev->state & NETDEV_OPEN )
return 0;
DBGC ( netdev, "NETDEV %p opening\n", netdev );
DBGC ( netdev, "NETDEV %s opening\n", netdev->name );
/* Mark as opened */
netdev->state |= NETDEV_OPEN;
/* Open the device */
if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
return rc;
/* Mark as opened */
netdev->state |= NETDEV_OPEN;
/* Add to head of open devices list */
list_add ( &netdev->open_list, &open_net_devices );
@@ -487,7 +490,7 @@ void netdev_close ( struct net_device *netdev ) {
if ( ! ( netdev->state & NETDEV_OPEN ) )
return;
DBGC ( netdev, "NETDEV %p closing\n", netdev );
DBGC ( netdev, "NETDEV %s closing\n", netdev->name );
/* Remove from open devices list */
list_del ( &netdev->open_list );
@@ -529,7 +532,7 @@ void unregister_netdev ( struct net_device *netdev ) {
/* Remove from device list */
list_del ( &netdev->list );
netdev_put ( netdev );
DBGC ( netdev, "NETDEV %p unregistered\n", netdev );
DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
}
/** Enable or disable interrupts
@@ -661,21 +664,19 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
ll_source );
}
DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
netdev, ntohs ( net_proto ) );
DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n",
netdev->name, ntohs ( net_proto ) );
free_iob ( iobuf );
return -ENOTSUP;
}
/**
* Single-step the network stack
*
* @v process Network stack process
* Poll the network stack
*
* This polls all interfaces for received packets, and processes
* packets from the RX queue.
*/
static void net_step ( struct process *process __unused ) {
void net_poll ( void ) {
struct net_device *netdev;
struct io_buffer *iobuf;
struct ll_protocol *ll_protocol;
@@ -690,6 +691,15 @@ static void net_step ( struct process *process __unused ) {
/* Poll for new packets */
netdev_poll ( netdev );
/* Leave received packets on the queue if receive
* queue processing is currently frozen. This will
* happen when the raw packets are to be manually
* dequeued using netdev_rx_dequeue(), rather than
* processed via the usual networking stack.
*/
if ( netdev_rx_frozen ( netdev ) )
continue;
/* Process at most one received packet. Give priority
* to getting packets out of the NIC over processing
* the received packets, because we advertise a window
@@ -698,8 +708,8 @@ static void net_step ( struct process *process __unused ) {
*/
if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
netdev, iobuf, iobuf->data,
DBGC ( netdev, "NETDEV %s processing %p (%p+%zx)\n",
netdev->name, iobuf, iobuf->data,
iob_len ( iobuf ) );
/* Remove link-layer header */
@@ -722,6 +732,15 @@ static void net_step ( struct process *process __unused ) {
}
}
/**
* Single-step the network stack
*
* @v process Network stack process
*/
static void net_step ( struct process *process __unused ) {
net_poll();
}
/** Networking stack process */
struct process net_process __permanent_process = {
.list = LIST_HEAD_INIT ( net_process.list ),
+5 -4
View File
@@ -12,6 +12,7 @@
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/uri.h>
#include <ipxe/netdevice.h>
#include <ipxe/tcpip.h>
#include <ipxe/tcp.h>
@@ -483,14 +484,14 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
start_timer ( &tcp->timer );
/* Allocate I/O buffer */
iobuf = alloc_iob ( len + MAX_HDR_LEN );
iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN );
if ( ! iobuf ) {
DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
"%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
tcp->rcv_ack );
return -ENOMEM;
}
iob_reserve ( iobuf, MAX_HDR_LEN );
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
/* Fill data payload from transmit queue */
tcp_process_tx_queue ( tcp, len, iobuf, 0 );
@@ -627,14 +628,14 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
int rc;
/* Allocate space for dataless TX buffer */
iobuf = alloc_iob ( MAX_HDR_LEN );
iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN );
if ( ! iobuf ) {
DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
"%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
return -ENOMEM;
}
iob_reserve ( iobuf, MAX_HDR_LEN );
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
/* Construct RST response */
tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
+20 -4
View File
@@ -59,6 +59,22 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
__einfo_error ( EINFO_EACCES_INCORRECT_TARGET_PASSWORD )
#define EINFO_EACCES_INCORRECT_TARGET_PASSWORD \
__einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect target password" )
#define EINVAL_ROOT_PATH_TOO_SHORT \
__einfo_error ( EINFO_EINVAL_ROOT_PATH_TOO_SHORT )
#define EINFO_EINVAL_ROOT_PATH_TOO_SHORT \
__einfo_uniqify ( EINFO_EINVAL, 0x01, "Root path too short" )
#define EINVAL_BAD_CREDENTIAL_MIX \
__einfo_error ( EINFO_EINVAL_BAD_CREDENTIAL_MIX )
#define EINFO_EINVAL_BAD_CREDENTIAL_MIX \
__einfo_uniqify ( EINFO_EINVAL, 0x02, "Bad credential mix" )
#define EINVAL_NO_ROOT_PATH \
__einfo_error ( EINFO_EINVAL_NO_ROOT_PATH )
#define EINFO_EINVAL_NO_ROOT_PATH \
__einfo_uniqify ( EINFO_EINVAL, 0x03, "No root path" )
#define EINVAL_NO_TARGET_IQN \
__einfo_error ( EINFO_EINVAL_NO_TARGET_IQN )
#define EINFO_EINVAL_NO_TARGET_IQN \
__einfo_uniqify ( EINFO_EINVAL, 0x04, "No target IQN" )
#define ENOTSUP_INITIATOR_STATUS \
__einfo_error ( EINFO_ENOTSUP_INITIATOR_STATUS )
#define EINFO_ENOTSUP_INITIATOR_STATUS \
@@ -1787,7 +1803,7 @@ static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
if ( ! *rp ) {
DBGC ( iscsi, "iSCSI %p root path \"%s\" "
"too short\n", iscsi, root_path );
return -EINVAL;
return -EINVAL_ROOT_PATH_TOO_SHORT;
}
}
*(rp++) = '\0';
@@ -1870,7 +1886,7 @@ static int iscsi_set_auth ( struct iscsi_session *iscsi,
( initiator_password ? "" : "no " ),
( target_username ? "" : "no " ),
( target_password ? "" : "no " ) );
return -EINVAL;
return -EINVAL_BAD_CREDENTIAL_MIX;
}
/**
@@ -1886,7 +1902,7 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) {
/* Sanity check */
if ( ! uri->opaque ) {
rc = -EINVAL;
rc = -EINVAL_NO_ROOT_PATH;
goto err_sanity_uri;
}
@@ -1924,7 +1940,7 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) {
if ( ! iscsi->target_iqn ) {
DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n",
iscsi, uri->opaque );
rc = -EINVAL;
rc = -EINVAL_NO_TARGET_IQN;
goto err_sanity_iqn;
}
+5 -3
View File
@@ -9,6 +9,7 @@
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/uri.h>
#include <ipxe/netdevice.h>
#include <ipxe/udp.h>
/** @file
@@ -197,7 +198,8 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
int rc;
/* Check we can accommodate the header */
if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) {
if ( ( rc = iob_ensure_headroom ( iobuf,
MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
free_iob ( iobuf );
return rc;
}
@@ -361,13 +363,13 @@ static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
size_t len ) {
struct io_buffer *iobuf;
iobuf = alloc_iob ( UDP_MAX_HLEN + len );
iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
if ( ! iobuf ) {
DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
udp, len );
return NULL;
}
iob_reserve ( iobuf, UDP_MAX_HLEN );
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
return iobuf;
}
+35 -29
View File
@@ -553,7 +553,8 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
/* Register settings */
parent = netdev_settings ( dhcp->netdev );
settings = &dhcppkt->settings;
if ( ( rc = register_settings ( settings, parent ) ) != 0 ) {
if ( ( rc = register_settings ( settings, parent,
DHCP_SETTINGS_NAME ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
dhcp, strerror ( rc ) );
dhcp_finished ( dhcp, rc );
@@ -568,9 +569,8 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
* without performing a ProxyDHCPREQUEST
*/
settings = &dhcp->proxy_offer->settings;
settings->name = PROXYDHCP_SETTINGS_NAME;
if ( ( rc = register_settings ( settings,
NULL ) ) != 0 ) {
if ( ( rc = register_settings ( settings, NULL,
PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not register "
"proxy settings: %s\n",
dhcp, strerror ( rc ) );
@@ -670,8 +670,8 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
return;
/* Register settings */
settings->name = PROXYDHCP_SETTINGS_NAME;
if ( ( rc = register_settings ( settings, NULL ) ) != 0 ) {
if ( ( rc = register_settings ( settings, NULL,
PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
dhcp, strerror ( rc ) );
dhcp_finished ( dhcp, rc );
@@ -809,8 +809,8 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
return;
/* Register settings */
dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
if ( ( rc = register_settings ( &dhcppkt->settings, NULL,
PXEBS_SETTINGS_NAME ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
dhcp, strerror ( rc ) );
dhcp_finished ( dhcp, rc );
@@ -867,20 +867,24 @@ static struct dhcp_session_state dhcp_state_pxebs = {
* Construct DHCP client hardware address field and broadcast flag
*
* @v netdev Network device
* @v hlen DHCP hardware address length to fill in
* @v flags DHCP flags to fill in
* @ret chaddr DHCP client hardware address
* @v chaddr Hardware address buffer
* @v flags Flags to set (or NULL)
* @ret hlen Hardware address length
*/
void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
uint16_t *flags ) {
unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
uint16_t *flags ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
typeof ( ( ( struct dhcphdr * ) NULL )->chaddr ) chaddr;
struct dhcphdr *dhcphdr;
int rc;
/* If the link-layer address cannot fit into the chaddr field
* (as is the case for IPoIB) then try using the hardware
* address instead. If we do this, set the broadcast flag,
* since chaddr then does not represent a valid link-layer
* address for the return path.
* (as is the case for IPoIB) then try using the Ethernet-
* compatible link-layer address. If we do this, set the
* broadcast flag, since chaddr then does not represent a
* valid link-layer address for the return path.
*
* If we cannot produce an Ethernet-compatible link-layer
* address, try using the hardware address.
*
* If even the hardware address is too large, use an empty
* chaddr field and set the broadcast flag.
@@ -891,16 +895,19 @@ void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
* storage, or by eliminating the hardware address completely
* from the DHCP packet, which seems unfriendly to users.
*/
if ( ( *hlen = ll_protocol->ll_addr_len ) <= sizeof ( chaddr ) ) {
return netdev->ll_addr;
if ( ll_protocol->ll_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
memcpy ( chaddr, netdev->ll_addr, ll_protocol->ll_addr_len );
return ll_protocol->ll_addr_len;
}
*flags = htons ( BOOTP_FL_BROADCAST );
if ( ( *hlen = ll_protocol->hw_addr_len ) <= sizeof ( chaddr ) ) {
return netdev->hw_addr;
} else {
*hlen = 0;
return NULL;
if ( flags )
*flags |= htons ( BOOTP_FL_BROADCAST );
if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, chaddr ) ) == 0 )
return ETH_ALEN;
if ( ll_protocol->hw_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
memcpy ( chaddr, netdev->hw_addr, ll_protocol->hw_addr_len );
return ll_protocol->hw_addr_len;
}
return 0;
}
/**
@@ -923,7 +930,6 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
const void *options, size_t options_len,
void *data, size_t max_len ) {
struct dhcphdr *dhcphdr = data;
void *chaddr;
int rc;
/* Sanity check */
@@ -936,8 +942,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
dhcphdr->op = dhcp_op[msgtype];
chaddr = dhcp_chaddr ( netdev, &dhcphdr->hlen, &dhcphdr->flags );
memcpy ( dhcphdr->chaddr, chaddr, dhcphdr->hlen );
dhcphdr->hlen = dhcp_chaddr ( netdev, dhcphdr->chaddr,
&dhcphdr->flags );
memcpy ( dhcphdr->options, options, options_len );
/* Initialise DHCP packet structure */

Some files were not shown because too many files have changed in this diff Show More