diff --git a/ChangeLog b/ChangeLog index 620d3fa41..ad1da08cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2012-06-09 Vladimir Serbinenko + + Keep TX and RX buffers on EFI rather than always allocate new ones. + + * include/grub/net.h (grub_net_card_driver): Allow driver to modify + card. All users updated. + (grub_net_card): New members txbuf, rcvbuf, rcvbufsize and txbusy. + * grub-core/net/drivers/efi/efinet.c (send_card_buffer): Reuse buffer. + (get_card_packet): Likewise. + (grub_efinet_findcards): Init new fields. + 2012-06-09 Vladimir Serbinenko * grub-core/term/ieee1275/serial.c (do_real_config): Fix cast to fix diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index 2313103de..e42eae745 100644 --- a/grub-core/net/drivers/efi/efinet.c +++ b/grub-core/net/drivers/efi/efinet.c @@ -31,37 +31,74 @@ static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; static grub_err_t -send_card_buffer (const struct grub_net_card *dev, +send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack) { grub_efi_status_t st; grub_efi_simple_network_t *net = dev->efi_net; grub_uint64_t limit_time = grub_get_time_ms () + 4000; - st = efi_call_7 (net->transmit, net, 0, (pack->tail - pack->data), - pack->data, NULL, NULL, NULL); + grub_size_t len; + + if (dev->txbusy) + while (1) + { + void *txbuf = NULL; + st = efi_call_3 (net->get_status, net, 0, &txbuf); + if (st != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, + N_("couldn't send network packet")); + if (txbuf == dev->txbuf) + { + dev->txbusy = 0; + break; + } + if (limit_time < grub_get_time_ms ()) + return grub_error (GRUB_ERR_TIMEOUT, N_("couldn't send network packet")); + } + + len = (pack->tail - pack->data); + if (len > dev->mtu) + len = dev->mtu; + + grub_memcpy (dev->txbuf, pack->data, len); + + st = efi_call_7 (net->transmit, net, 0, len, + dev->txbuf, NULL, NULL, NULL); if (st != GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_IO, N_("couldn't send network packet")); - while (1) - { - void *txbuf = NULL; - st = efi_call_3 (net->get_status, net, 0, &txbuf); - if (st != GRUB_EFI_SUCCESS) - return grub_error (GRUB_ERR_IO, N_("couldn't send network packet")); - if (txbuf) - return GRUB_ERR_NONE; - if (limit_time < grub_get_time_ms ()) - return grub_error (GRUB_ERR_TIMEOUT, N_("couldn't send network packet")); - } + dev->txbusy = 1; + return GRUB_ERR_NONE; } static struct grub_net_buff * -get_card_packet (const struct grub_net_card *dev) +get_card_packet (struct grub_net_card *dev) { grub_efi_simple_network_t *net = dev->efi_net; grub_err_t err; grub_efi_status_t st; - grub_efi_uintn_t bufsize = 1536; + grub_efi_uintn_t bufsize = dev->rcvbufsize; struct grub_net_buff *nb; + int i; + + for (i = 0; i < 2; i++) + { + if (!dev->rcvbuf) + dev->rcvbuf = grub_malloc (dev->rcvbufsize); + if (!dev->rcvbuf) + return NULL; + + st = efi_call_7 (net->receive, net, NULL, &bufsize, + dev->rcvbuf, NULL, NULL, NULL); + if (st != GRUB_EFI_BUFFER_TOO_SMALL) + break; + dev->rcvbufsize = 2 * ALIGN_UP (dev->rcvbufsize > bufsize + ? dev->rcvbufsize : bufsize, 64); + grub_free (dev->rcvbuf); + dev->rcvbuf = 0; + } + + if (st != GRUB_EFI_SUCCESS) + return NULL; nb = grub_netbuff_alloc (bufsize + 2); if (!nb) @@ -74,35 +111,7 @@ get_card_packet (const struct grub_net_card *dev) grub_netbuff_free (nb); return NULL; } - - st = efi_call_7 (net->receive, net, NULL, &bufsize, - nb->data, NULL, NULL, NULL); - if (st == GRUB_EFI_BUFFER_TOO_SMALL) - { - grub_netbuff_free (nb); - - bufsize = ALIGN_UP (bufsize, 32); - - nb = grub_netbuff_alloc (bufsize + 2); - if (!nb) - return NULL; - - /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible - by 4. So that IP header is aligned on 4 bytes. */ - if (grub_netbuff_reserve (nb, 2)) - { - grub_netbuff_free (nb); - return NULL; - } - - st = efi_call_7 (net->receive, net, NULL, &bufsize, - nb->data, NULL, NULL, NULL); - } - if (st != GRUB_EFI_SUCCESS) - { - grub_netbuff_free (nb); - return NULL; - } + grub_memcpy (nb->data, dev->rcvbuf, bufsize); err = grub_netbuff_put (nb, bufsize); if (err) { @@ -171,11 +180,23 @@ grub_efinet_findcards (void) return; } + card->mtu = net->mode->max_packet_size; + card->txbuf = grub_zalloc (ALIGN_UP (card->mtu, 64) + 256); + if (!card->txbuf) + { + grub_print_error (); + grub_free (handles); + grub_free (card); + return; + } + card->txbusy = 0; + + card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256; + card->name = grub_xasprintf ("efinet%d", i++); card->driver = &efidriver; card->flags = 0; card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; - card->mtu = net->mode->max_packet_size; grub_memcpy (card->default_address.mac, net->mode->current_address, sizeof (card->default_address.mac)); diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c index 245b8780a..6fc89dfb1 100644 --- a/grub-core/net/drivers/emu/emunet.c +++ b/grub-core/net/drivers/emu/emunet.c @@ -34,7 +34,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); static int fd; static grub_err_t -send_card_buffer (const struct grub_net_card *dev __attribute__ ((unused)), +send_card_buffer (struct grub_net_card *dev __attribute__ ((unused)), struct grub_net_buff *pack) { ssize_t actual; @@ -47,7 +47,7 @@ send_card_buffer (const struct grub_net_card *dev __attribute__ ((unused)), } static struct grub_net_buff * -get_card_packet (const struct grub_net_card *dev __attribute__ ((unused))) +get_card_packet (struct grub_net_card *dev __attribute__ ((unused))) { ssize_t actual; struct grub_net_buff *nb; diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c index 27003f5ff..c4de613bc 100644 --- a/grub-core/net/drivers/i386/pc/pxe.c +++ b/grub-core/net/drivers/i386/pc/pxe.c @@ -167,7 +167,7 @@ grub_pxe_scan (void) } static struct grub_net_buff * -grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused))) +grub_pxe_recv (struct grub_net_card *dev __attribute__ ((unused))) { struct grub_pxe_undi_isr *isr; static int in_progress = 0; @@ -250,7 +250,7 @@ grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused))) } static grub_err_t -grub_pxe_send (const struct grub_net_card *dev __attribute__ ((unused)), +grub_pxe_send (struct grub_net_card *dev __attribute__ ((unused)), struct grub_net_buff *pack) { struct grub_pxe_undi_transmit *trans; @@ -276,7 +276,7 @@ grub_pxe_send (const struct grub_net_card *dev __attribute__ ((unused)), } static void -grub_pxe_close (const struct grub_net_card *dev __attribute__ ((unused))) +grub_pxe_close (struct grub_net_card *dev __attribute__ ((unused))) { if (pxe_rm_entry) grub_pxe_call (GRUB_PXENV_UNDI_CLOSE, @@ -285,7 +285,7 @@ grub_pxe_close (const struct grub_net_card *dev __attribute__ ((unused))) } static grub_err_t -grub_pxe_open (const struct grub_net_card *dev __attribute__ ((unused))) +grub_pxe_open (struct grub_net_card *dev __attribute__ ((unused))) { struct grub_pxe_undi_open *ou; ou = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c index a1fcf0839..fb9f31cf6 100644 --- a/grub-core/net/drivers/ieee1275/ofnet.c +++ b/grub-core/net/drivers/ieee1275/ofnet.c @@ -32,7 +32,7 @@ struct grub_ofnetcard_data }; static grub_err_t -card_open (const struct grub_net_card *dev) +card_open (struct grub_net_card *dev) { int status; struct grub_ofnetcard_data *data = dev->data; @@ -51,7 +51,7 @@ card_open (const struct grub_net_card *dev) } static void -card_close (const struct grub_net_card *dev) +card_close (struct grub_net_card *dev) { struct grub_ofnetcard_data *data = dev->data; @@ -60,7 +60,7 @@ card_close (const struct grub_net_card *dev) } static grub_err_t -send_card_buffer (const struct grub_net_card *dev, struct grub_net_buff *pack) +send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack) { grub_ssize_t actual; int status; @@ -75,7 +75,7 @@ send_card_buffer (const struct grub_net_card *dev, struct grub_net_buff *pack) } static struct grub_net_buff * -get_card_packet (const struct grub_net_card *dev) +get_card_packet (struct grub_net_card *dev) { grub_ssize_t actual; int rc; diff --git a/include/grub/net.h b/include/grub/net.h index 7d6f06733..bd6d87ae9 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -74,11 +74,11 @@ struct grub_net_card_driver struct grub_net_card_driver *next; struct grub_net_card_driver **prev; const char *name; - grub_err_t (*open) (const struct grub_net_card *dev); - void (*close) (const struct grub_net_card *dev); - grub_err_t (*send) (const struct grub_net_card *dev, + grub_err_t (*open) (struct grub_net_card *dev); + void (*close) (struct grub_net_card *dev); + grub_err_t (*send) (struct grub_net_card *dev, struct grub_net_buff *buf); - struct grub_net_buff * (*recv) (const struct grub_net_card *dev); + struct grub_net_buff * (*recv) (struct grub_net_card *dev); }; typedef struct grub_net_packet @@ -126,6 +126,10 @@ struct grub_net_card struct grub_net_slaac_mac_list *slaac_list; grub_ssize_t new_ll_entry; struct grub_net_link_layer_entry *link_layer_table; + void *txbuf; + void *rcvbuf; + grub_size_t rcvbufsize; + int txbusy; union { #ifdef GRUB_MACHINE_EFI