[PATCH 5/8] usbnet: smsc95xx: align tx-buffer to word

From: Ben Dooks
Date: Fri Oct 12 2018 - 04:34:58 EST


The tegra EHCI driver requires alignment of the buffer, so try and
make this better by pushing the buffer start back to an word
aligned address. At the worst this makes memcpy() easier as
it is word aligned, at best it makes sure the usb can directly
map the buffer.

Signed-off-by: Ben Dooks <ben.dooks@xxxxxxxxxxxxxxx>
---
Changes since v1:
- Removed the module parameter
- Reworked the tx code to ensure retry if alignment changed
- Explicitly mention the EHCI in the tegra
- Deal with new simpler tx code
---
drivers/net/usb/Kconfig | 12 ++++++++++++
drivers/net/usb/smsc95xx.c | 22 +++++++++++++++++++---
2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index c3ebc43a6582..1af6fb0cadb1 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -364,6 +364,18 @@ config USB_NET_SMSC95XX_TURBO
soft-irq load, thus making it useful to default the option
off for these.

+config USB_NET_SMSC95XX_TXALIGN
+ bool "Add bytes to align transmit buffers"
+ depends on USB_NET_SMSC95XX
+ default n
+ help
+ This option makes the tx buffers 32 bit aligned which might
+ help with systems that want tx data aligned to a 32 bit
+ boundary.
+
+ Using this option will mean there may be up to 3 bytes of
+ data per packet sent.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 19e71fe15f6c..8ce190da8be0 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -2017,28 +2017,43 @@ static bool smsc95xx_can_tx_checksum(struct sk_buff *skb)
return skb->csum_offset < (len - (4 + 1));
}

+static inline u32 tx_align(struct sk_buff *skb)
+{
+#ifdef CONFIG_USB_NET_SMSC95XX_TXALIGN
+ return ((u32)skb->data) & 3;
+#else
+ return 0;
+#endif
+}
+
static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags)
{
bool csum = skb->ip_summed == CHECKSUM_PARTIAL;
int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
u32 tx_cmd_a, tx_cmd_b;
+ u32 align;
void *ptr;

/* We do not advertise SG, so skbs should be already linearized */
BUG_ON(skb_shinfo(skb)->nr_frags);

+retry_align:
+ align = tx_align(skb);
+
/* Make writable and expand header space by overhead if required */
- if (skb_cow_head(skb, overhead)) {
+ if (skb_cow_head(skb, overhead + align)) {
/* Must deallocate here as returning NULL to indicate error
* means the skb won't be deallocated in the caller.
*/
dev_kfree_skb_any(skb);
return NULL;
- }
+ } else if (tx_align(skb) != align)
+ goto retry_align;

tx_cmd_b = (u32)skb->len;
tx_cmd_a = tx_cmd_b | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+ tx_cmd_a |= align << 16;

if (csum) {
if (!smsc95xx_can_tx_checksum(skb)) {
@@ -2062,7 +2077,8 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
}
}

- ptr = skb_push(skb, 8);
+ /* TX command format is in section 5.4 of SMSC95XX datasbook */
+ ptr = skb_push(skb, 8 + align);
put_unaligned_le32(tx_cmd_a, ptr);
put_unaligned_le32(tx_cmd_b, ptr+4);

--
2.19.1