mirror of
https://github.com/ipxe/ipxe
synced 2026-05-16 15:00:48 +03:00
adcaaf9b93
Some past security reviews carried out for UEFI Secure Boot signing submissions have covered specific drivers or functional areas of iPXE. Mark all of the files comprising these areas as permitted for UEFI Secure Boot. Signed-off-by: Michael Brown <mcb30@ipxe.org>
301 lines
8.4 KiB
C
301 lines
8.4 KiB
C
#ifndef _SMSCUSB_H
|
|
#define _SMSCUSB_H
|
|
|
|
/** @file
|
|
*
|
|
* SMSC USB Ethernet drivers
|
|
*
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
FILE_SECBOOT ( PERMITTED );
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <byteswap.h>
|
|
#include <ipxe/usb.h>
|
|
#include <ipxe/usbnet.h>
|
|
#include <ipxe/netdevice.h>
|
|
#include <ipxe/mii.h>
|
|
#include <ipxe/if_ether.h>
|
|
|
|
/** Register write command */
|
|
#define SMSCUSB_REGISTER_WRITE \
|
|
( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
|
|
USB_REQUEST_TYPE ( 0xa0 ) )
|
|
|
|
/** Register read command */
|
|
#define SMSCUSB_REGISTER_READ \
|
|
( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
|
|
USB_REQUEST_TYPE ( 0xa1 ) )
|
|
|
|
/** Get statistics command */
|
|
#define SMSCUSB_GET_STATISTICS \
|
|
( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
|
|
USB_REQUEST_TYPE ( 0xa2 ) )
|
|
|
|
/** EEPROM command register offset */
|
|
#define SMSCUSB_E2P_CMD 0x000
|
|
#define SMSCUSB_E2P_CMD_EPC_BSY 0x80000000UL /**< EPC busy */
|
|
#define SMSCUSB_E2P_CMD_EPC_CMD_READ 0x00000000UL /**< READ command */
|
|
#define SMSCUSB_E2P_CMD_EPC_ADDR(addr) ( (addr) << 0 ) /**< EPC address */
|
|
|
|
/** EEPROM data register offset */
|
|
#define SMSCUSB_E2P_DATA 0x004
|
|
#define SMSCUSB_E2P_DATA_GET(e2p_data) \
|
|
( ( (e2p_data) >> 0 ) & 0xff ) /**< EEPROM data */
|
|
|
|
/** MAC address EEPROM address */
|
|
#define SMSCUSB_EEPROM_MAC 0x01
|
|
|
|
/** Maximum time to wait for EEPROM (in milliseconds) */
|
|
#define SMSCUSB_EEPROM_MAX_WAIT_MS 100
|
|
|
|
/** OTP power register offset */
|
|
#define SMSCUSB_OTP_POWER 0x000
|
|
#define SMSCUSB_OTP_POWER_DOWN 0x00000001UL /**< OTP power down */
|
|
|
|
/** OTP address high byte register offset */
|
|
#define SMSCUSB_OTP_ADDRH 0x004
|
|
|
|
/** OTP address low byte register offset */
|
|
#define SMSCUSB_OTP_ADDRL 0x008
|
|
|
|
/** OTP data register offset */
|
|
#define SMSCUSB_OTP_DATA 0x018
|
|
#define SMSCUSB_OTP_DATA_GET(otp_data) \
|
|
( ( (otp_data) >> 0 ) & 0xff ) /**< OTP data */
|
|
|
|
/** OTP command selection register offset */
|
|
#define SMSCUSB_OTP_CMD 0x020
|
|
#define SMSCUSB_OTP_CMD_READ 0x00000001UL /**< Read command */
|
|
|
|
/** OTP command initiation register offset */
|
|
#define SMSCUSB_OTP_GO 0x028
|
|
#define SMSCUSB_OTP_GO_GO 0x00000001UL /**< Initiate command */
|
|
|
|
/** OTP status register offset */
|
|
#define SMSCUSB_OTP_STATUS 0x030
|
|
#define SMSCUSB_OTP_STATUS_BUSY 0x00000001UL /**< OTP busy */
|
|
|
|
/** Maximum time to wait for OTP (in milliseconds) */
|
|
#define SMSCUSB_OTP_MAX_WAIT_MS 100
|
|
|
|
/** OTP layout 1 signature */
|
|
#define SMSCUSB_OTP_1_SIG 0xf3
|
|
|
|
/** OTP layout 1 MAC address offset */
|
|
#define SMSCUSB_OTP_1_MAC 0x001
|
|
|
|
/** OTP layout 2 signature */
|
|
#define SMSCUSB_OTP_2_SIG 0xf7
|
|
|
|
/** OTP layout 2 MAC address offset */
|
|
#define SMSCUSB_OTP_2_MAC 0x101
|
|
|
|
/** MII access register offset */
|
|
#define SMSCUSB_MII_ACCESS 0x000
|
|
#define SMSCUSB_MII_ACCESS_PHY_ADDRESS 0x00000800UL /**< PHY address */
|
|
#define SMSCUSB_MII_ACCESS_MIIRINDA(addr) ( (addr) << 6 ) /**< MII register */
|
|
#define SMSCUSB_MII_ACCESS_MIIWNR 0x00000002UL /**< MII write */
|
|
#define SMSCUSB_MII_ACCESS_MIIBZY 0x00000001UL /**< MII busy */
|
|
|
|
/** MII data register offset */
|
|
#define SMSCUSB_MII_DATA 0x004
|
|
#define SMSCUSB_MII_DATA_SET(data) ( (data) << 0 ) /**< Set data */
|
|
#define SMSCUSB_MII_DATA_GET(mii_data) \
|
|
( ( (mii_data) >> 0 ) & 0xffff ) /**< Get data */
|
|
|
|
/** Maximum time to wait for MII (in milliseconds) */
|
|
#define SMSCUSB_MII_MAX_WAIT_MS 100
|
|
|
|
/** MAC address */
|
|
union smscusb_mac {
|
|
/** MAC receive address registers */
|
|
struct {
|
|
/** MAC receive address low register */
|
|
uint32_t l;
|
|
/** MAC receive address high register */
|
|
uint32_t h;
|
|
} __attribute__ (( packed )) addr;
|
|
/** Raw MAC address */
|
|
uint8_t raw[ETH_ALEN];
|
|
};
|
|
|
|
/** MAC receive address high register offset */
|
|
#define SMSCUSB_RX_ADDRH 0x000
|
|
|
|
/** MAC receive address low register offset */
|
|
#define SMSCUSB_RX_ADDRL 0x004
|
|
|
|
/** MAC address perfect filter N high register offset */
|
|
#define SMSCUSB_ADDR_FILTH(n) ( 0x000 + ( 8 * (n) ) )
|
|
#define SMSCUSB_ADDR_FILTH_VALID 0x80000000UL /**< Address valid */
|
|
|
|
/** MAC address perfect filter N low register offset */
|
|
#define SMSCUSB_ADDR_FILTL(n) ( 0x004 + ( 8 * (n) ) )
|
|
|
|
/** Interrupt packet format */
|
|
struct smscusb_interrupt {
|
|
/** Current value of INT_STS register */
|
|
uint32_t int_sts;
|
|
} __attribute__ (( packed ));
|
|
|
|
/** An SMSC USB device */
|
|
struct smscusb_device {
|
|
/** USB device */
|
|
struct usb_device *usb;
|
|
/** USB bus */
|
|
struct usb_bus *bus;
|
|
/** Network device */
|
|
struct net_device *netdev;
|
|
/** USB network device */
|
|
struct usbnet_device usbnet;
|
|
/** MII interface */
|
|
struct mii_interface mdio;
|
|
/** MII device */
|
|
struct mii_device mii;
|
|
/** MII register base */
|
|
uint16_t mii_base;
|
|
/** PHY interrupt source register */
|
|
uint16_t phy_source;
|
|
/** Interrupt status */
|
|
uint32_t int_sts;
|
|
};
|
|
|
|
extern int smscusb_raw_writel ( struct smscusb_device *smscusb,
|
|
unsigned int address, uint32_t value );
|
|
extern int smscusb_raw_readl ( struct smscusb_device *smscusb,
|
|
unsigned int address, uint32_t *value );
|
|
|
|
/**
|
|
* Write register
|
|
*
|
|
* @v smscusb SMSC USB device
|
|
* @v address Register address
|
|
* @v value Register value
|
|
* @ret rc Return status code
|
|
*/
|
|
static inline __attribute__ (( always_inline )) int
|
|
smscusb_writel ( struct smscusb_device *smscusb, unsigned int address,
|
|
uint32_t value ) {
|
|
int rc;
|
|
|
|
/* Write register */
|
|
if ( ( rc = smscusb_raw_writel ( smscusb, address,
|
|
cpu_to_le32 ( value ) ) ) != 0 )
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Read register
|
|
*
|
|
* @v smscusb SMSC USB device
|
|
* @v address Register address
|
|
* @ret value Register value
|
|
* @ret rc Return status code
|
|
*/
|
|
static inline __attribute__ (( always_inline )) int
|
|
smscusb_readl ( struct smscusb_device *smscusb, unsigned int address,
|
|
uint32_t *value ) {
|
|
int rc;
|
|
|
|
/* Read register */
|
|
if ( ( rc = smscusb_raw_readl ( smscusb, address, value ) ) != 0 )
|
|
return rc;
|
|
le32_to_cpus ( value );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get statistics
|
|
*
|
|
* @v smscusb SMSC USB device
|
|
* @v index Statistics set index
|
|
* @v data Statistics data to fill in
|
|
* @v len Length of statistics data
|
|
* @ret rc Return status code
|
|
*/
|
|
static inline __attribute__ (( always_inline )) int
|
|
smscusb_get_statistics ( struct smscusb_device *smscusb, unsigned int index,
|
|
void *data, size_t len ) {
|
|
int rc;
|
|
|
|
/* Read statistics */
|
|
if ( ( rc = usb_control ( smscusb->usb, SMSCUSB_GET_STATISTICS, 0,
|
|
index, data, len ) ) != 0 ) {
|
|
DBGC ( smscusb, "SMSCUSB %p could not get statistics set %d: "
|
|
"%s\n", smscusb, index, strerror ( rc ) );
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** Interrupt maximum fill level
|
|
*
|
|
* This is a policy decision.
|
|
*/
|
|
#define SMSCUSB_INTR_MAX_FILL 2
|
|
|
|
extern struct usb_endpoint_driver_operations smscusb_intr_operations;
|
|
extern struct usb_endpoint_driver_operations smscusb_out_operations;
|
|
extern struct mii_operations smscusb_mii_operations;
|
|
|
|
/**
|
|
* Initialise SMSC USB device
|
|
*
|
|
* @v smscusb SMSC USB device
|
|
* @v netdev Network device
|
|
* @v func USB function
|
|
* @v in Bulk IN endpoint operations
|
|
*/
|
|
static inline __attribute__ (( always_inline )) void
|
|
smscusb_init ( struct smscusb_device *smscusb, struct net_device *netdev,
|
|
struct usb_function *func,
|
|
struct usb_endpoint_driver_operations *in ) {
|
|
struct usb_device *usb = func->usb;
|
|
|
|
smscusb->usb = usb;
|
|
smscusb->bus = usb->port->hub->bus;
|
|
smscusb->netdev = netdev;
|
|
usbnet_init ( &smscusb->usbnet, func, &smscusb_intr_operations, in,
|
|
&smscusb_out_operations );
|
|
usb_refill_init ( &smscusb->usbnet.intr, 0, 0, SMSCUSB_INTR_MAX_FILL );
|
|
}
|
|
|
|
/**
|
|
* Initialise SMSC USB device MII interface
|
|
*
|
|
* @v smscusb SMSC USB device
|
|
* @v mii_base MII register base
|
|
* @v phy_source Interrupt source PHY register
|
|
*/
|
|
static inline __attribute__ (( always_inline )) void
|
|
smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base,
|
|
unsigned int phy_source ) {
|
|
|
|
mdio_init ( &smscusb->mdio, &smscusb_mii_operations );
|
|
mii_init ( &smscusb->mii, &smscusb->mdio, 0 );
|
|
smscusb->mii_base = mii_base;
|
|
smscusb->phy_source = phy_source;
|
|
}
|
|
|
|
extern int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
|
|
unsigned int e2p_base );
|
|
extern int smscusb_otp_fetch_mac ( struct smscusb_device *smscusb,
|
|
unsigned int otp_base );
|
|
extern int smscusb_fdt_fetch_mac ( struct smscusb_device *smscusb );
|
|
extern int smscusb_mii_check_link ( struct smscusb_device *smscusb );
|
|
extern int smscusb_mii_open ( struct smscusb_device *smscusb,
|
|
unsigned int phy_mask, unsigned int intrs );
|
|
extern int smscusb_set_address ( struct smscusb_device *smscusb,
|
|
unsigned int addr_base );
|
|
extern int smscusb_set_filter ( struct smscusb_device *smscusb,
|
|
unsigned int filt_base );
|
|
|
|
#endif /* _SMSCUSB_H */
|