From: Sascha Hauer <s.hauer@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH 3/7] net: Add EFI Simple Network Protocol Driver
Date: Fri, 11 Jul 2014 09:36:26 +0200 [thread overview]
Message-ID: <1405064190-1977-4-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1405064190-1977-1-git-send-email-s.hauer@pengutronix.de>
This adds a network driver which uses the EFI Simple Network
Protocol to implement networking for barebox.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/net/Kconfig | 4 +
drivers/net/Makefile | 1 +
drivers/net/efi-snp.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 301 insertions(+)
create mode 100644 drivers/net/efi-snp.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5f0c41b..43409a8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -170,6 +170,10 @@ config DRIVER_NET_TAP
bool "tap Ethernet driver"
depends on LINUX
+config DRIVER_NET_EFI_SNP
+ bool "EFI SNP ethernet driver"
+ depends on ARCH_EFI
+
config DRIVER_NET_TSE
depends on NIOS2
bool "Altera TSE ethernet driver"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 33bb5c8..1b85778 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
+obj-$(CONFIG_DRIVER_NET_EFI_SNP) += efi-snp.o
diff --git a/drivers/net/efi-snp.c b/drivers/net/efi-snp.c
new file mode 100644
index 0000000..5b96fbf
--- /dev/null
+++ b/drivers/net/efi-snp.c
@@ -0,0 +1,296 @@
+/*
+ * efi-snp.c - Simple Network Protocol driver for EFI
+ *
+ * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <efi.h>
+#include <mach/efi.h>
+#include <mach/efi-device.h>
+
+struct efi_network_statistics {
+ uint64_t RxTotalFrames;
+ uint64_t RxGoodFrames;
+ uint64_t RxUndersizeFrames;
+ uint64_t RxOversizeFrames;
+ uint64_t RxDroppedFrames;
+ uint64_t RxUnicastFrames;
+ uint64_t RxBroadcastFrames;
+ uint64_t RxMulticastFrames;
+ uint64_t RxCrcErrorFrames;
+ uint64_t RxTotalBytes;
+ uint64_t TxTotalFrames;
+ uint64_t TxGoodFrames;
+ uint64_t TxUndersizeFrames;
+ uint64_t TxOversizeFrames;
+ uint64_t TxDroppedFrames;
+ uint64_t TxUnicastFrames;
+ uint64_t TxBroadcastFrames;
+ uint64_t TxMulticastFrames;
+ uint64_t TxCrcErrorFrames;
+ uint64_t TxTotalBytes;
+ uint64_t Collisions;
+ uint64_t UnsupportedProtocol;
+};
+
+enum efi_simple_network_state {
+ EfiSimpleNetworkStopped,
+ EfiSimpleNetworkStarted,
+ EfiSimpleNetworkInitialized,
+ EfiSimpleNetworkMaxState
+};
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01
+#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02
+#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04
+#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08
+
+#define MAX_MCAST_FILTER_CNT 16
+struct efi_simple_network_mode {
+ uint32_t State;
+ uint32_t HwAddressSize;
+ uint32_t MediaHeaderSize;
+ uint32_t MaxPacketSize;
+ uint32_t NvRamSize;
+ uint32_t NvRamAccessSize;
+ uint32_t ReceiveFilterMask;
+ 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;
+ uint8_t IfType;
+ bool MacAddressChangeable;
+ bool MultipleTxSupported;
+ bool MediaPresentSupported;
+ bool MediaPresent;
+};
+
+#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION 0x00010000
+
+struct efi_simple_network {
+ uint64_t Revision;
+ efi_status_t (EFIAPI *start) (struct efi_simple_network *This);
+ efi_status_t (EFIAPI *stop) (struct efi_simple_network *This);
+ efi_status_t (EFIAPI *initialize) (struct efi_simple_network *This,
+ unsigned long ExtraRxBufferSize, unsigned long ExtraTxBufferSize);
+ efi_status_t (EFIAPI *reset) (struct efi_simple_network *This, bool ExtendedVerification);
+ 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);
+ efi_status_t (EFIAPI *station_address) (struct efi_simple_network *This,
+ bool Reset, 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);
+ efi_status_t (EFIAPI *nvdata) (struct efi_simple_network *This,
+ bool ReadWrite, unsigned long Offset, unsigned long BufferSize,
+ void *Buffer);
+ efi_status_t (EFIAPI *get_status) (struct efi_simple_network *This,
+ 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,
+ 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);
+ void *WaitForPacket;
+ struct efi_simple_network_mode *Mode;
+};
+
+struct efi_snp_priv {
+ struct device_d *dev;
+ struct eth_device edev;
+ struct efi_simple_network *snp;
+};
+
+static inline struct efi_snp_priv *to_priv(struct eth_device *edev)
+{
+ return container_of(edev, struct efi_snp_priv, edev);
+}
+
+static int efi_snp_eth_send(struct eth_device *edev, void *packet, int length)
+{
+ struct efi_snp_priv *priv = to_priv(edev);
+ efi_status_t efiret;
+ void *txbuf;
+ uint64_t start;
+
+ 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));
+ return -efi_errno(efiret);
+ }
+
+ start = get_time_ns();
+
+ while (!is_timeout(start, SECOND)) {
+ uint32_t irq;
+ priv->snp->get_status(priv->snp, &irq, &txbuf);
+ if (txbuf)
+ return 0;
+ }
+
+ dev_err(priv->dev, "tx time out\n");
+
+ return -ETIMEDOUT;
+}
+
+static int efi_snp_eth_rx(struct eth_device *edev)
+{
+ struct efi_snp_priv *priv = to_priv(edev);
+ long bufsize = PKTSIZE;
+ efi_status_t efiret;
+
+ efiret = priv->snp->receive(priv->snp, NULL, &bufsize, NetRxPackets[0], NULL, NULL, NULL);
+ if (efiret == EFI_NOT_READY)
+ return 0;
+
+ if (EFI_ERROR(efiret)) {
+ dev_err(priv->dev, "failed to receive: %s\n", efi_strerror(efiret));
+ return -efi_errno(efiret);
+ }
+
+ net_receive(edev, NetRxPackets[0], bufsize);
+
+ return 0;
+}
+
+static int efi_snp_eth_open(struct eth_device *edev)
+{
+ struct efi_snp_priv *priv = to_priv(edev);
+ uint32_t mask;
+ efi_status_t efiret;
+
+ priv->snp->shutdown(priv->snp);
+ priv->snp->stop(priv->snp);
+ priv->snp->start(priv->snp);
+ efiret = priv->snp->initialize(priv->snp, 0, 0);
+ if (EFI_ERROR(efiret)) {
+ dev_err(priv->dev, "Initialize failed with: %s\n", efi_strerror(efiret));
+ return -efi_errno(efiret);
+ }
+
+ efiret = priv->snp->station_address(priv->snp, false,
+ (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));
+ return -efi_errno(efiret);
+ }
+
+ mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ efiret = priv->snp->receive_filters(priv->snp, mask, 0, 0, 0, 0);
+ if (EFI_ERROR(efiret)) {
+ dev_err(priv->dev, "failed to set receive filters: %s\n",
+ efi_strerror(efiret));
+ return -efi_errno(efiret);
+ }
+
+ return 0;
+}
+
+static void efi_snp_eth_halt(struct eth_device *edev)
+{
+ struct efi_snp_priv *priv = to_priv(edev);
+
+ priv->snp->stop(priv->snp);
+}
+
+static int efi_snp_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ struct efi_snp_priv *priv = to_priv(edev);
+
+ memcpy(adr, priv->snp->Mode->PermanentAddress.Addr, 6);
+
+ return 0;
+}
+
+static int efi_snp_set_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ return 0;
+}
+
+int efi_snp_probe(struct efi_device *efidev)
+{
+ struct eth_device *edev;
+ struct efi_snp_priv *priv;
+ int ret;
+
+ dev_dbg(&efidev->dev, "efi_snp_probe\n");
+
+ priv = xzalloc(sizeof(struct efi_snp_priv));
+ priv->snp = efidev->protocol;
+ priv->dev = &efidev->dev;
+
+ dev_dbg(&efidev->dev, "perm: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ priv->snp->Mode->PermanentAddress.Addr[0],
+ priv->snp->Mode->PermanentAddress.Addr[1],
+ priv->snp->Mode->PermanentAddress.Addr[2],
+ priv->snp->Mode->PermanentAddress.Addr[3],
+ priv->snp->Mode->PermanentAddress.Addr[4],
+ priv->snp->Mode->PermanentAddress.Addr[5]);
+ dev_dbg(&efidev->dev, "curr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ priv->snp->Mode->CurrentAddress.Addr[0],
+ priv->snp->Mode->CurrentAddress.Addr[1],
+ priv->snp->Mode->CurrentAddress.Addr[2],
+ priv->snp->Mode->CurrentAddress.Addr[3],
+ priv->snp->Mode->CurrentAddress.Addr[4],
+ priv->snp->Mode->CurrentAddress.Addr[5]);
+
+ edev = &priv->edev;
+ edev->priv = priv;
+ edev->parent = &efidev->dev;
+
+ edev->open = efi_snp_eth_open;
+ edev->send = efi_snp_eth_send;
+ edev->recv = efi_snp_eth_rx;
+ edev->halt = efi_snp_eth_halt;
+ edev->get_ethaddr = efi_snp_get_ethaddr;
+ edev->set_ethaddr = efi_snp_set_ethaddr;
+
+ ret = eth_register(edev);
+
+ return ret;
+}
+
+static struct efi_driver efi_snp_driver = {
+ .driver = {
+ .name = "efi-snp",
+ },
+ .probe = efi_snp_probe,
+ .guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID,
+};
+device_efi_driver(efi_snp_driver);
--
2.0.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2014-07-11 7:38 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-11 7:36 [PATCH v2] Initial EFI support Sascha Hauer
2014-07-11 7:36 ` [PATCH 1/7] Documentation: Add EFI documentation Sascha Hauer
2014-07-11 7:36 ` Sascha Hauer [this message]
2014-07-11 7:36 ` [PATCH 4/7] serial: Add EFI stdio driver Sascha Hauer
2014-07-11 7:36 ` [PATCH 5/7] fs: implement EFI filesystem driver Sascha Hauer
2014-07-11 7:36 ` [PATCH 6/7] fs: implement EFI variable " Sascha Hauer
2014-07-11 7:36 ` [PATCH 7/7] EFI: introduce efi_strguid to convert GUID to human readable names Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1405064190-1977-4-git-send-email-s.hauer@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox