예제 #1
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Get station addresses
 *
 * @v nii		NII NIC
 * @v netdev		Network device to fill in
 * @ret rc		Return status code
 */
static int nii_get_station_address ( struct nii_nic *nii,
				     struct net_device *netdev ) {
	PXE_DB_STATION_ADDRESS db;
	int stat;
	int rc;

	/* Initialise UNDI */
	if ( ( rc = nii_initialise ( nii ) ) != 0 )
		goto err_initialise;

	/* Issue command */
	if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_STATION_ADDRESS, &db,
				     sizeof ( db ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not get station address: %s\n",
		       nii->dev.name, strerror ( rc ) );
		goto err_station_address;
	}

	/* Copy MAC addresses */
	memcpy ( netdev->ll_addr, db.StationAddr,
		 netdev->ll_protocol->ll_addr_len );
	memcpy ( netdev->hw_addr, db.PermanentAddr,
		 netdev->ll_protocol->hw_addr_len );
	memcpy ( nii->broadcast, db.BroadcastAddr,
		 sizeof ( nii->broadcast ) );

 err_station_address:
	nii_shutdown ( nii );
 err_initialise:
	return rc;
}
예제 #2
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Poll for completed packets
 *
 * @v netdev		Network device
 */
static void nii_poll ( struct net_device *netdev ) {
	struct nii_nic *nii = netdev->priv;
	PXE_DB_GET_STATUS db;
	unsigned int op;
	int stat;
	int rc;

	/* Construct data block */
	memset ( &db, 0, sizeof ( db ) );

	/* Get status */
	op = NII_OP ( PXE_OPCODE_GET_STATUS,
		      ( PXE_OPFLAGS_GET_INTERRUPT_STATUS |
			( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)|
			( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) );
	if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not get status: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return;
	}

	/* Process any TX completions */
	if ( nii->txbuf )
		nii_poll_tx ( netdev, stat );

	/* Process any RX completions */
	nii_poll_rx ( netdev );

	/* Check for link state changes */
	if ( nii->media )
		nii_poll_link ( netdev, stat );
}
예제 #3
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int nii_transmit ( struct net_device *netdev,
			  struct io_buffer *iobuf ) {
	struct nii_nic *nii = netdev->priv;
	PXE_CPB_TRANSMIT cpb;
	int stat;
	int rc;

	/* Defer the packet if there is already a transmission in progress */
	if ( nii->txbuf ) {
		netdev_tx_defer ( netdev, iobuf );
		return 0;
	}

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	cpb.FrameAddr = virt_to_bus ( iobuf->data );
	cpb.DataLen = iob_len ( iobuf );
	cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len;

	/* Transmit packet */
	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb,
				      sizeof ( cpb ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not transmit: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}
	nii->txbuf = iobuf;

	return 0;
}
예제 #4
0
/**
 * Set receive filters
 *
 * @v nii		NII NIC
 * @ret rc		Return status code
 */
static int nii_set_rx_filters ( struct nii_nic *nii ) {
	uint32_t implementation = nii->undi->Implementation;
	unsigned int flags;
	unsigned int op;
	int stat;
	int rc;

	/* Construct receive filter set */
	flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
		  PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
	if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
		flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
	if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
		flags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
	if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED )
		flags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;

	/* Issue command */
	op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
	if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n",
		       nii->dev.name, flags, strerror ( rc ) );
		return rc;
	}

	return 0;
}
예제 #5
0
/**
 * Set station address
 *
 * @v nii		NII NIC
 * @v netdev		Network device
 * @ret rc		Return status code
 */
static int nii_set_station_address ( struct nii_nic *nii,
				     struct net_device *netdev ) {
	uint32_t implementation = nii->undi->Implementation;
	PXE_CPB_STATION_ADDRESS cpb;
	unsigned int op;
	int stat;
	int rc;

	/* Fail if setting station address is unsupported */
	if ( ! ( implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE ) )
		return -ENOTSUP;

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	memcpy ( cpb.StationAddr, netdev->ll_addr,
		 netdev->ll_protocol->ll_addr_len );

	/* Issue command */
	op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
	              PXE_OPFLAGS_STATION_ADDRESS_WRITE );
	if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not set station address: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}

	return 0;
}
예제 #6
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Stop UNDI
 *
 * @v nii		NII NIC
 */
static void nii_stop_undi ( struct nii_nic *nii ) {
	int stat;
	int rc;

	/* Issue command */
	if ( ( stat = nii_issue ( nii, PXE_OPCODE_STOP ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not stop: %s\n",
		       nii->dev.name, strerror ( rc ) );
		/* Nothing we can do about it */
		return;
	}
}
예제 #7
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void nii_poll_rx ( struct net_device *netdev ) {
	struct nii_nic *nii = netdev->priv;
	PXE_CPB_RECEIVE cpb;
	PXE_DB_RECEIVE db;
	unsigned int quota;
	int stat;
	int rc;

	/* Retrieve up to NII_RX_QUOTA packets */
	for ( quota = NII_RX_QUOTA ; quota ; quota-- ) {

		/* Allocate buffer, if required */
		if ( ! nii->rxbuf ) {
			nii->rxbuf = alloc_iob ( nii->mtu );
			if ( ! nii->rxbuf ) {
				/* Leave for next poll */
				break;
			}
		}

		/* Construct parameter block */
		memset ( &cpb, 0, sizeof ( cpb ) );
		cpb.BufferAddr = virt_to_bus ( nii->rxbuf->data );
		cpb.BufferLen = iob_tailroom ( nii->rxbuf );

		/* Issue command */
		if ( ( stat = nii_issue_cpb_db ( nii, PXE_OPCODE_RECEIVE,
						 &cpb, sizeof ( cpb ),
						 &db, sizeof ( db ) ) ) < 0 ) {

			/* PXE_STATCODE_NO_DATA is just the usual "no packet"
			 * status indicator; ignore it.
			 */
			if ( stat == -PXE_STATCODE_NO_DATA )
				break;

			/* Anything else is an error */
			rc = -EIO_STAT ( stat );
			DBGC ( nii, "NII %s could not receive: %s\n",
			       nii->dev.name, strerror ( rc ) );
			netdev_rx_err ( netdev, NULL, rc );
			break;
		}

		/* Hand off to network stack */
		iob_put ( nii->rxbuf, db.FrameLen );
		netdev_rx ( netdev, nii->rxbuf );
		nii->rxbuf = NULL;
	}
}
예제 #8
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Shut down UNDI
 *
 * @v nii		NII NIC
 */
static void nii_shutdown ( struct nii_nic *nii ) {
	int stat;
	int rc;

	/* Issue command */
	if ( ( stat = nii_issue ( nii, PXE_OPCODE_SHUTDOWN ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not shut down: %s\n",
		       nii->dev.name, strerror ( rc ) );
		/* Leak memory to avoid corruption */
		return;
	}

	/* Free buffer */
	ufree ( nii->buffer );
}
예제 #9
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Set receive filters
 *
 * @v nii		NII NIC
 * @ret rc		Return status code
 */
static int nii_set_rx_filters ( struct nii_nic *nii ) {
	unsigned int op;
	int stat;
	int rc;

	/* Issue command */
	op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS,
		      ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
			PXE_OPFLAGS_RECEIVE_FILTER_UNICAST |
			PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
			PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
			PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST ) );
	if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not set receive filters: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}

	return 0;
}
예제 #10
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Initialise UNDI
 *
 * @v nii		NII NIC
 * @ret rc		Return status code
 */
static int nii_initialise ( struct nii_nic *nii ) {
	PXE_CPB_INITIALIZE cpb;
	PXE_DB_INITIALIZE db;
	unsigned int op;
	int stat;
	int rc;

	/* Allocate memory buffer */
	nii->buffer = umalloc ( nii->buffer_len );
	if ( ! nii->buffer ) {
		rc = -ENOMEM;
		goto err_alloc;
	}

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	cpb.MemoryAddr = ( ( intptr_t ) nii->buffer );
	cpb.MemoryLength = nii->buffer_len;

	/* Construct data block */
	memset ( &db, 0, sizeof ( db ) );

	/* Issue command */
	op = NII_OP ( PXE_OPCODE_INITIALIZE,
		      PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE );
	if ( ( stat = nii_issue_cpb_db ( nii, op, &cpb, sizeof ( cpb ),
					 &db, sizeof ( db ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not initialise: %s\n",
		       nii->dev.name, strerror ( rc ) );
		goto err_initialize;
	}

	return 0;

 err_initialize:
	ufree ( nii->buffer );
 err_alloc:
	return rc;
}
예제 #11
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Set station address
 *
 * @v nii		NII NIC
 * @v netdev		Network device
 * @ret rc		Return status code
 */
static int nii_set_station_address ( struct nii_nic *nii,
				     struct net_device *netdev ) {
	PXE_CPB_STATION_ADDRESS cpb;
	int stat;
	int rc;

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	memcpy ( cpb.StationAddr, netdev->ll_addr,
		 netdev->ll_protocol->ll_addr_len );

	/* Issue command */
	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS,
				      &cpb, sizeof ( cpb ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not set station address: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}

	return 0;
}
예제 #12
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Get initialisation information
 *
 * @v nii		NII NIC
 * @v netdev		Network device to fill in
 * @ret rc		Return status code
 */
static int nii_get_init_info ( struct nii_nic *nii,
			       struct net_device *netdev ) {
	PXE_DB_GET_INIT_INFO db;
	int stat;
	int rc;

	/* Issue command */
	if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_GET_INIT_INFO, &db,
				     sizeof ( db ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not get initialisation info: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}

	/* Determine link layer protocol */
	switch ( db.IFtype ) {
	case PXE_IFTYPE_ETHERNET :
		netdev->ll_protocol = &ethernet_protocol;
		break;
	default:
		DBGC ( nii, "NII %s unknown interface type %#02x\n",
		       nii->dev.name, db.IFtype );
		return -ENOTSUP;
	}

	/* Sanity checks */
	assert ( db.MediaHeaderLen == netdev->ll_protocol->ll_header_len );
	assert ( db.HWaddrLen == netdev->ll_protocol->hw_addr_len );
	assert ( db.HWaddrLen == netdev->ll_protocol->ll_addr_len );

	/* Extract parameters */
	nii->buffer_len = db.MemoryRequired;
	nii->mtu = ( db.FrameDataLen + db.MediaHeaderLen );
	netdev->max_pkt_len = nii->mtu;
	nii->media = ( stat & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED );

	return 0;
}
예제 #13
0
파일: nii.c 프로젝트: baloo/ipxe
/**
 * Start UNDI
 *
 * @v nii		NII NIC
 * @ret rc		Return status code
 */
static int nii_start_undi ( struct nii_nic *nii ) {
	PXE_CPB_START_31 cpb;
	int stat;
	int rc;

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	cpb.Delay = ( ( intptr_t ) nii_delay );
	cpb.Block = ( ( intptr_t ) nii_block );
	cpb.Mem_IO = ( ( intptr_t ) nii_io );
	cpb.Unique_ID = ( ( intptr_t ) nii );

	/* Issue command */
	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_START, &cpb,
				      sizeof ( cpb ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not start: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}

	return 0;
}