diff options
Diffstat (limited to 'drivers/net/efi-snp.c')
-rw-r--r-- | drivers/net/efi-snp.c | 89 |
1 files changed, 73 insertions, 16 deletions
diff --git a/drivers/net/efi-snp.c b/drivers/net/efi-snp.c index def2714bee..476015f1c2 100644 --- a/drivers/net/efi-snp.c +++ b/drivers/net/efi-snp.c @@ -11,7 +11,7 @@ #include <net.h> #include <init.h> #include <efi.h> -#include <efi/efi.h> +#include <efi/efi-payload.h> #include <efi/efi-device.h> struct efi_network_statistics { @@ -69,10 +69,10 @@ struct efi_simple_network_mode { uint32_t ReceiveFilterSetting; uint32_t MaxMCastFilterCount; uint32_t MCastFilterCount; - efi_mac_address MCastFilter[MAX_MCAST_FILTER_CNT]; - efi_mac_address CurrentAddress; - efi_mac_address BroadcastAddress; - efi_mac_address PermanentAddress; + struct efi_mac_address MCastFilter[MAX_MCAST_FILTER_CNT]; + struct efi_mac_address CurrentAddress; + struct efi_mac_address BroadcastAddress; + struct efi_mac_address PermanentAddress; uint8_t IfType; bool MacAddressChangeable; bool MultipleTxSupported; @@ -92,14 +92,14 @@ struct efi_simple_network { efi_status_t (EFIAPI *shutdown) (struct efi_simple_network *This); efi_status_t (EFIAPI *receive_filters) (struct efi_simple_network *This, uint32_t Enable, uint32_t Disable, bool ResetMCastFilter, - unsigned long MCastFilterCnt, efi_mac_address *MCastFilter); + unsigned long MCastFilterCnt, struct efi_mac_address *MCastFilter); efi_status_t (EFIAPI *station_address) (struct efi_simple_network *This, - bool Reset, efi_mac_address *New); + bool Reset, struct efi_mac_address *New); efi_status_t (EFIAPI *statistics) (struct efi_simple_network *This, bool Reset, unsigned long *StatisticsSize, struct efi_network_statistics *StatisticsTable); efi_status_t (EFIAPI *mcast_ip_to_mac) (struct efi_simple_network *This, - bool IPv6, efi_ip_address *IP, efi_mac_address *MAC); + bool IPv6, union efi_ip_address *IP, struct efi_mac_address *MAC); efi_status_t (EFIAPI *nvdata) (struct efi_simple_network *This, bool ReadWrite, unsigned long Offset, unsigned long BufferSize, void *Buffer); @@ -107,19 +107,20 @@ struct efi_simple_network { uint32_t *InterruptStatus, void **TxBuf); efi_status_t (EFIAPI *transmit) (struct efi_simple_network *This, unsigned long HeaderSize, unsigned long BufferSize, void *Buffer, - efi_mac_address *SrcAddr, efi_mac_address *DestAddr, + struct efi_mac_address *SrcAddr, struct efi_mac_address *DestAddr, uint16_t *Protocol); efi_status_t (EFIAPI *receive) (struct efi_simple_network *This, unsigned long *HeaderSize, unsigned long *BufferSize, void *Buffer, - efi_mac_address *SrcAddr, efi_mac_address *DestAddr, uint16_t *Protocol); + struct efi_mac_address *SrcAddr, struct efi_mac_address *DestAddr, uint16_t *Protocol); void *WaitForPacket; struct efi_simple_network_mode *Mode; }; struct efi_snp_priv { - struct device_d *dev; + struct device *dev; struct eth_device edev; struct efi_simple_network *snp; + void *rx_buf; }; static inline struct efi_snp_priv *to_priv(struct eth_device *edev) @@ -134,6 +135,9 @@ static int efi_snp_eth_send(struct eth_device *edev, void *packet, int length) void *txbuf; uint64_t start; + if (!priv->snp->Mode->MediaPresent) + return -ENOMEDIUM; + efiret = priv->snp->transmit(priv->snp, 0, length, packet, NULL, NULL, NULL); if (EFI_ERROR(efiret)) { dev_err(priv->dev, "failed to send: %s\n", efi_strerror(efiret)); @@ -160,7 +164,7 @@ static int efi_snp_eth_rx(struct eth_device *edev) long bufsize = PKTSIZE; efi_status_t efiret; - efiret = priv->snp->receive(priv->snp, NULL, &bufsize, NetRxPackets[0], NULL, NULL, NULL); + efiret = priv->snp->receive(priv->snp, NULL, &bufsize, priv->rx_buf, NULL, NULL, NULL); if (efiret == EFI_NOT_READY) return 0; @@ -169,11 +173,37 @@ static int efi_snp_eth_rx(struct eth_device *edev) return -efi_errno(efiret); } - net_receive(edev, NetRxPackets[0], bufsize); + net_receive(edev, priv->rx_buf, bufsize); return 0; } +static efi_guid_t snp_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; + +static int efi_snp_open_exclusive(struct efi_device *efidev) +{ + void *interface; + efi_status_t efiret; + + /* + * Try to re-open SNP exlusively to close any active MNP protocol instance + * that may compete for packet polling + */ + efiret = BS->open_protocol(efidev->handle, &snp_guid, + &interface, efi_parent_image, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); + if (EFI_ERROR(efiret)) { + dev_err(&efidev->dev, "failed to open exclusively: %s\n", efi_strerror(efiret)); + return -efi_errno(efiret); + } + + return 0; +} + +static void efi_snp_close_exclusive(struct efi_device *efidev) +{ + BS->close_protocol(efidev->handle, &snp_guid, efi_parent_image, NULL); +} + static int efi_snp_eth_open(struct eth_device *edev) { struct efi_snp_priv *priv = to_priv(edev); @@ -190,7 +220,7 @@ static int efi_snp_eth_open(struct eth_device *edev) } efiret = priv->snp->station_address(priv->snp, false, - (efi_mac_address *)priv->snp->Mode->PermanentAddress.Addr ); + (struct efi_mac_address *)priv->snp->Mode->PermanentAddress.Addr ); if (EFI_ERROR(efiret)) { dev_err(priv->dev, "failed to set MAC address: %s\n", efi_strerror(efiret)); @@ -231,6 +261,20 @@ static int efi_snp_set_ethaddr(struct eth_device *edev, const unsigned char *adr return 0; } +static int efi_snp_pause(struct efi_device *efidev) +{ + efi_snp_close_exclusive(efidev); + + return 0; +} + +static int efi_snp_continue(struct efi_device *efidev) +{ + efi_snp_open_exclusive(efidev); + + return 0; +} + static int efi_snp_probe(struct efi_device *efidev) { struct eth_device *edev; @@ -242,6 +286,7 @@ static int efi_snp_probe(struct efi_device *efidev) priv = xzalloc(sizeof(struct efi_snp_priv)); priv->snp = efidev->protocol; priv->dev = &efidev->dev; + priv->rx_buf = xmalloc(PKTSIZE); dev_dbg(&efidev->dev, "perm: %02x:%02x:%02x:%02x:%02x:%02x\n", priv->snp->Mode->PermanentAddress.Addr[0], @@ -269,16 +314,28 @@ static int efi_snp_probe(struct efi_device *efidev) edev->get_ethaddr = efi_snp_get_ethaddr; edev->set_ethaddr = efi_snp_set_ethaddr; + ret = efi_snp_open_exclusive(efidev); + if (ret) + return ret; + ret = eth_register(edev); return ret; } +static void efi_snp_remove(struct efi_device *efidev) +{ + efi_snp_close_exclusive(efidev); +} + static struct efi_driver efi_snp_driver = { - .driver = { + .driver = { .name = "efi-snp", }, - .probe = efi_snp_probe, + .probe = efi_snp_probe, + .remove = efi_snp_remove, + .dev_pause = efi_snp_pause, + .dev_continue = efi_snp_continue, .guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID, }; device_efi_driver(efi_snp_driver); |