mirror of
https://github.com/xcat2/xNBA.git
synced 2025-01-11 10:17:49 +00:00
Merge branch 'master' of /pub/scm/gpxe
This commit is contained in:
commit
4bcfe7507b
@ -45,8 +45,20 @@ struct undi_nic {
|
||||
unsigned int irq;
|
||||
/** Currently processing ISR */
|
||||
int isr_processing;
|
||||
/** Bug workarounds */
|
||||
int hacks;
|
||||
};
|
||||
|
||||
/**
|
||||
* @defgroup undi_hacks UNDI workarounds
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Work around Etherboot 5.4 bugs */
|
||||
#define UNDI_HACK_EB54 0x0001
|
||||
|
||||
/** @} */
|
||||
|
||||
static void undinet_close ( struct net_device *netdev );
|
||||
|
||||
/*****************************************************************************
|
||||
@ -245,6 +257,9 @@ static struct segoff prev_handler[ IRQ_MAX + 1 ];
|
||||
static volatile uint8_t __text16 ( trigger_count ) = 0;
|
||||
#define trigger_count __use_text16 ( trigger_count )
|
||||
|
||||
/** Last observed trigger count */
|
||||
static unsigned int last_trigger_count = 0;
|
||||
|
||||
/**
|
||||
* Hook UNDI interrupt service routine
|
||||
*
|
||||
@ -292,7 +307,6 @@ static void undinet_unhook_isr ( unsigned int irq ) {
|
||||
* @ret triggered ISR has been triggered since last check
|
||||
*/
|
||||
static int undinet_isr_triggered ( void ) {
|
||||
static unsigned int last_trigger_count = 0;
|
||||
unsigned int this_trigger_count;
|
||||
|
||||
/* Read trigger_count. Do this only once; it is volatile */
|
||||
@ -333,6 +347,16 @@ static int undinet_transmit ( struct net_device *netdev,
|
||||
size_t len = iob_len ( iobuf );
|
||||
int rc;
|
||||
|
||||
/* Technically, we ought to make sure that the previous
|
||||
* transmission has completed before we re-use the buffer.
|
||||
* However, many PXE stacks (including at least some Intel PXE
|
||||
* stacks and Etherboot 5.4) fail to generate TX completions.
|
||||
* In practice this won't be a problem, since our TX datapath
|
||||
* has a very low packet volume and we can get away with
|
||||
* assuming that a TX will be complete by the time we want to
|
||||
* transmit the next packet.
|
||||
*/
|
||||
|
||||
/* Copy packet to UNDI I/O buffer */
|
||||
if ( len > sizeof ( basemem_packet ) )
|
||||
len = sizeof ( basemem_packet );
|
||||
@ -460,9 +484,15 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
||||
undi_isr.Frame.segment,
|
||||
undi_isr.Frame.offset, frag_len );
|
||||
if ( iob_len ( iobuf ) == len ) {
|
||||
/* Whole packet received; deliver it */
|
||||
netdev_rx ( netdev, iobuf );
|
||||
iobuf = NULL;
|
||||
--rx_quota;
|
||||
/* Etherboot 5.4 fails to return all packets
|
||||
* under mild load; pretend it retriggered.
|
||||
*/
|
||||
if ( undinic->hacks & UNDI_HACK_EB54 )
|
||||
--last_trigger_count;
|
||||
}
|
||||
break;
|
||||
case PXENV_UNDI_ISR_OUT_DONE:
|
||||
@ -582,6 +612,7 @@ int undinet_probe ( struct undi_device *undi ) {
|
||||
struct s_PXENV_UNDI_STARTUP undi_startup;
|
||||
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
|
||||
struct s_PXENV_UNDI_GET_INFORMATION undi_info;
|
||||
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
|
||||
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
|
||||
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
|
||||
struct s_PXENV_STOP_UNDI stop_undi;
|
||||
@ -639,6 +670,21 @@ int undinet_probe ( struct undi_device *undi ) {
|
||||
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
|
||||
undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq );
|
||||
|
||||
/* Get interface information */
|
||||
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
|
||||
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
|
||||
&undi_iface,
|
||||
sizeof ( undi_iface ) ) ) != 0 )
|
||||
goto err_undi_get_iface_info;
|
||||
DBGC ( undinic, "UNDINIC %p has type %s and link speed %ld\n",
|
||||
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed );
|
||||
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
|
||||
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
|
||||
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
|
||||
undinic );
|
||||
undinic->hacks |= UNDI_HACK_EB54;
|
||||
}
|
||||
|
||||
/* Point to NIC specific routines */
|
||||
netdev->open = undinet_open;
|
||||
netdev->close = undinet_close;
|
||||
@ -653,6 +699,7 @@ int undinet_probe ( struct undi_device *undi ) {
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
err_undi_get_iface_info:
|
||||
err_bad_irq:
|
||||
err_undi_get_information:
|
||||
err_undi_initialize:
|
||||
|
@ -529,7 +529,7 @@ static int isapnp_try_isolate ( void ) {
|
||||
*
|
||||
*/
|
||||
static void isapnp_isolate ( void ) {
|
||||
for ( isapnp_read_port = ISAPNP_READ_PORT_MIN ;
|
||||
for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
|
||||
isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
|
||||
isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
|
||||
/* Avoid problematic locations such as the NE2000
|
||||
|
@ -57,12 +57,17 @@ static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
||||
}
|
||||
}
|
||||
|
||||
static int legacy_open ( struct net_device *netdev __unused ) {
|
||||
static int legacy_open ( struct net_device *netdev ) {
|
||||
struct nic *nic = netdev->priv;
|
||||
|
||||
nic->nic_op->irq ( nic, ENABLE );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void legacy_close ( struct net_device *netdev __unused ) {
|
||||
/* Nothing to do */
|
||||
static void legacy_close ( struct net_device *netdev ) {
|
||||
struct nic *nic = netdev->priv;
|
||||
|
||||
nic->nic_op->irq ( nic, DISABLE );
|
||||
}
|
||||
|
||||
int legacy_probe ( void *hwdev,
|
||||
|
@ -160,29 +160,6 @@ static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
IRQ - Handle card interrupt status
|
||||
***************************************************************************/
|
||||
#if 0
|
||||
static void pnic_irq ( struct net_device *netdev, irq_action_t action ) {
|
||||
struct pnic *pnic = netdev->priv;
|
||||
uint8_t enabled;
|
||||
|
||||
switch ( action ) {
|
||||
case DISABLE :
|
||||
case ENABLE :
|
||||
enabled = ( action == ENABLE ? 1 : 0 );
|
||||
pnic_command ( pnic, PNIC_CMD_MASK_IRQ,
|
||||
&enabled, sizeof ( enabled ), NULL, 0, NULL );
|
||||
break;
|
||||
case FORCE :
|
||||
pnic_command ( pnic, PNIC_CMD_FORCE_IRQ,
|
||||
NULL, 0, NULL, 0, NULL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
OPEN - Open network device
|
||||
***************************************************************************/
|
||||
|
@ -380,8 +380,7 @@ static int rtl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
||||
|
||||
/* Check for space in TX ring */
|
||||
if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) {
|
||||
printf ( "TX overflow\n" );
|
||||
free_iob ( iobuf );
|
||||
DBG ( "TX overflow\n" );
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
@ -472,34 +471,6 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void rtl_irq(struct nic *nic, irq_action_t action)
|
||||
{
|
||||
unsigned int mask;
|
||||
/* Bit of a guess as to which interrupts we should allow */
|
||||
unsigned int interested = ROK | RER | RXOVW | FOVW | SERR;
|
||||
|
||||
switch ( action ) {
|
||||
case DISABLE :
|
||||
case ENABLE :
|
||||
mask = inw(rtl->ioaddr + IntrMask);
|
||||
mask = mask & ~interested;
|
||||
if ( action == ENABLE ) mask = mask | interested;
|
||||
outw(mask, rtl->ioaddr + IntrMask);
|
||||
break;
|
||||
case FORCE :
|
||||
/* Apparently writing a 1 to this read-only bit of a
|
||||
* read-only and otherwise unrelated register will
|
||||
* force an interrupt. If you ever want to see how
|
||||
* not to write a datasheet, read the one for the
|
||||
* RTL8139...
|
||||
*/
|
||||
outb(EROK, rtl->ioaddr + RxEarlyStatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
|
@ -49,7 +49,8 @@
|
||||
/* Port addresses */
|
||||
#define ISAPNP_ADDRESS 0x279
|
||||
#define ISAPNP_WRITE_DATA 0xa79
|
||||
#define ISAPNP_READ_PORT_MIN 0x213 /* ISAPnP spec says 0x203, but
|
||||
#define ISAPNP_READ_PORT_MIN 0x203
|
||||
#define ISAPNP_READ_PORT_START 0x213 /* ISAPnP spec says 0x203, but
|
||||
* Linux ISAPnP starts at
|
||||
* 0x213 with no explanatory
|
||||
* comment. 0x203 probably
|
||||
@ -63,6 +64,10 @@
|
||||
* any value less than 16.
|
||||
*/
|
||||
|
||||
/* Card select numbers */
|
||||
#define ISAPNP_CSN_MIN 0x01
|
||||
#define ISAPNP_CSN_MAX 0x0f
|
||||
|
||||
/* Registers */
|
||||
#define ISAPNP_READPORT 0x00
|
||||
#define ISAPNP_SERIALISOLATION 0x01
|
||||
|
@ -289,8 +289,9 @@ netdev_put ( struct net_device *netdev ) {
|
||||
}
|
||||
|
||||
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||
void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||
void netdev_tx_complete_next ( struct net_device *netdev );
|
||||
extern void netdev_tx_complete ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf );
|
||||
extern void netdev_tx_complete_next ( struct net_device *netdev );
|
||||
extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||
extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota );
|
||||
extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
|
||||
@ -299,9 +300,9 @@ extern int register_netdev ( struct net_device *netdev );
|
||||
extern int netdev_open ( struct net_device *netdev );
|
||||
extern void netdev_close ( struct net_device *netdev );
|
||||
extern void unregister_netdev ( struct net_device *netdev );
|
||||
struct net_device * find_netdev ( const char *name );
|
||||
struct net_device * find_pci_netdev ( unsigned int busdevfn );
|
||||
|
||||
extern struct net_device * find_netdev ( const char *name );
|
||||
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
||||
unsigned int location );
|
||||
extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
struct net_protocol *net_protocol, const void *ll_dest );
|
||||
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <gpxe/uaccess.h>
|
||||
#include <gpxe/dhcp.h>
|
||||
#include <gpxe/device.h>
|
||||
#include <gpxe/netdevice.h>
|
||||
#include <gpxe/isapnp.h>
|
||||
#include <basemem_packet.h>
|
||||
#include "pxe.h"
|
||||
#include "pxe_call.h"
|
||||
@ -196,41 +199,47 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
|
||||
* Status: working
|
||||
*/
|
||||
PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
|
||||
unsigned int isapnp_read_port;
|
||||
unsigned int isapnp_csn;
|
||||
unsigned int pci_busdevfn;
|
||||
unsigned int bus_type;
|
||||
unsigned int location;
|
||||
struct net_device *netdev;
|
||||
|
||||
DBG ( "PXENV_START_UNDI" );
|
||||
DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
|
||||
start_undi->AX, start_undi->BX, start_undi->DX );
|
||||
|
||||
#if 0
|
||||
/* Record PCI bus & devfn passed by caller, so we know which
|
||||
* NIC they want to use.
|
||||
*
|
||||
* If they don't match our already-existing NIC structure, set
|
||||
* values to ensure that the specified NIC is used at the next
|
||||
* call to pxe_intialise_nic().
|
||||
*/
|
||||
bus = ( start_undi->AX >> 8 ) & 0xff;
|
||||
devfn = start_undi->AX & 0xff;
|
||||
/* Determine bus type and location */
|
||||
isapnp_read_port = start_undi->DX;
|
||||
isapnp_csn = start_undi->BX;
|
||||
pci_busdevfn = start_undi->AX;
|
||||
|
||||
#warning "device probing mechanism has completely changed"
|
||||
#if 0
|
||||
if ( ( pci->dev.driver == NULL ) ||
|
||||
( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
|
||||
/* This is quite a bit of a hack and relies on
|
||||
* knowledge of the internal operation of Etherboot's
|
||||
* probe mechanism.
|
||||
*/
|
||||
DBG ( " set PCI %hhx:%hhx.%hhx",
|
||||
bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
|
||||
dev->type = BOOT_NIC;
|
||||
dev->to_probe = PROBE_PCI;
|
||||
memset ( &dev->state, 0, sizeof(dev->state) );
|
||||
pci->advance = 1;
|
||||
pci->dev.use_specified = 1;
|
||||
pci->dev.bus = bus;
|
||||
pci->dev.devfn = devfn;
|
||||
/* Use a heuristic to decide whether we are PCI or ISAPnP */
|
||||
if ( ( isapnp_read_port >= ISAPNP_READ_PORT_MIN ) &&
|
||||
( isapnp_read_port <= ISAPNP_READ_PORT_MAX ) &&
|
||||
( isapnp_csn >= ISAPNP_CSN_MIN ) &&
|
||||
( isapnp_csn <= ISAPNP_CSN_MAX ) ) {
|
||||
bus_type = BUS_TYPE_ISAPNP;
|
||||
location = isapnp_csn;
|
||||
} else {
|
||||
bus_type = BUS_TYPE_PCI;
|
||||
location = pci_busdevfn;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Look for a matching net device */
|
||||
netdev = find_netdev_by_location ( bus_type, location );
|
||||
if ( ! netdev ) {
|
||||
DBG ( " no net device found" );
|
||||
start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
|
||||
return PXENV_EXIT_FAILURE;
|
||||
}
|
||||
DBG ( " using netdev %s", netdev->name );
|
||||
|
||||
/* Save as PXE net device */
|
||||
pxe_set_netdev ( netdev );
|
||||
|
||||
/* Hook INT 1A */
|
||||
pxe_hook_int1a();
|
||||
|
||||
start_undi->Status = PXENV_STATUS_SUCCESS;
|
||||
return PXENV_EXIT_SUCCESS;
|
||||
|
@ -394,18 +394,15 @@ PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
|
||||
|
||||
/* PXENV_UNDI_FORCE_INTERRUPT
|
||||
*
|
||||
* Status: working
|
||||
* Status: won't implement (would require driver API changes for no
|
||||
* perceptible benefit)
|
||||
*/
|
||||
PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
|
||||
*undi_force_interrupt ) {
|
||||
DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
|
||||
|
||||
#if 0
|
||||
eth_irq ( FORCE );
|
||||
#endif
|
||||
|
||||
undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
|
||||
return PXENV_EXIT_SUCCESS;
|
||||
undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
|
||||
return PXENV_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* PXENV_UNDI_GET_MCAST_ADDRESS
|
||||
@ -483,7 +480,7 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
|
||||
* Most PXE stacks seem to take this approach.
|
||||
*/
|
||||
snprintf ( ( char * ) undi_get_iface_info->IfaceType,
|
||||
sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" );
|
||||
sizeof ( undi_get_iface_info->IfaceType ), "gPXE" );
|
||||
undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
|
||||
undi_get_iface_info->ServiceFlags = 0;
|
||||
memset ( undi_get_iface_info->Reserved, 0,
|
||||
|
@ -141,12 +141,20 @@ void del_ipv4_address ( struct net_device *netdev ) {
|
||||
* @v dest Final destination address
|
||||
* @ret dest Next hop destination address
|
||||
* @ret miniroute Routing table entry to use, or NULL if no route
|
||||
*
|
||||
* If the route requires use of a gateway, the next hop destination
|
||||
* address will be overwritten with the gateway address.
|
||||
*/
|
||||
static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
|
||||
struct ipv4_miniroute *miniroute;
|
||||
int local;
|
||||
int has_gw;
|
||||
|
||||
/* Never attempt to route the broadcast address */
|
||||
if ( dest->s_addr == INADDR_BROADCAST )
|
||||
return NULL;
|
||||
|
||||
/* Find first usable route in routing table */
|
||||
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
||||
local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
|
||||
& miniroute->netmask.s_addr ) == 0 );
|
||||
|
@ -356,15 +356,17 @@ struct net_device * find_netdev ( const char *name ) {
|
||||
/**
|
||||
* Get network device by PCI bus:dev.fn address
|
||||
*
|
||||
* @v busdevfn PCI bus:dev.fn address
|
||||
* @v bus_type Bus type
|
||||
* @v location Bus location
|
||||
* @ret netdev Network device, or NULL
|
||||
*/
|
||||
struct net_device * find_pci_netdev ( unsigned int busdevfn ) {
|
||||
struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
||||
unsigned int location ) {
|
||||
struct net_device *netdev;
|
||||
|
||||
list_for_each_entry ( netdev, &net_devices, list ) {
|
||||
if ( ( netdev->dev->desc.bus_type == BUS_TYPE_PCI ) &&
|
||||
( netdev->dev->desc.location == busdevfn ) )
|
||||
if ( ( netdev->dev->desc.bus_type == bus_type ) &&
|
||||
( netdev->dev->desc.location == location ) )
|
||||
return netdev;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user