Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351460
b: refs/heads/master
c: 8b5b6f5
h: refs/heads/master
v: v3
  • Loading branch information
Lucas Stach authored and David S. Miller committed Jan 18, 2013
1 parent 115c515 commit 65cec50
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5620df65d81292c5fb1beba8d380ef58cd98b53f
refs/heads/master: 8b5b6f5413e97c3e8bafcdd67553d508f4f698cd
15 changes: 14 additions & 1 deletion trunk/drivers/net/usb/asix.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ struct asix_data {
u8 res;
};

struct asix_rx_fixup_info {
struct sk_buff *ax_skb;
u32 header;
u16 size;
bool split_head;
};

struct asix_common_private {
struct asix_rx_fixup_info rx_fixup_info;
};

/* ASIX specific flags */
#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */

Expand All @@ -179,7 +190,9 @@ int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
u16 index, u16 size, void *data);

int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
struct asix_rx_fixup_info *rx);
int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);

struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags);
Expand Down
90 changes: 65 additions & 25 deletions trunk/drivers/net/usb/asix_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,49 +51,89 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
value, index, data, size);
}

int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
struct asix_rx_fixup_info *rx)
{
int offset = 0;

while (offset + sizeof(u32) < skb->len) {
struct sk_buff *ax_skb;
u16 size;
u32 header = get_unaligned_le32(skb->data + offset);

offset += sizeof(u32);

/* get the packet length */
size = (u16) (header & 0x7ff);
if (size != ((~header >> 16) & 0x07ff)) {
netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
return 0;
while (offset + sizeof(u16) <= skb->len) {
u16 remaining = 0;
unsigned char *data;

if (!rx->size) {
if ((skb->len - offset == sizeof(u16)) ||
rx->split_head) {
if(!rx->split_head) {
rx->header = get_unaligned_le16(
skb->data + offset);
rx->split_head = true;
offset += sizeof(u16);
break;
} else {
rx->header |= (get_unaligned_le16(
skb->data + offset)
<< 16);
rx->split_head = false;
offset += sizeof(u16);
}
} else {
rx->header = get_unaligned_le32(skb->data +
offset);
offset += sizeof(u32);
}

/* get the packet length */
rx->size = (u16) (rx->header & 0x7ff);
if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
rx->header, offset);
rx->size = 0;
return 0;
}
rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
rx->size);
if (!rx->ax_skb)
return 0;
}

if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
(size + offset > skb->len)) {
if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
size);
rx->size);
kfree_skb(rx->ax_skb);
return 0;
}
ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
if (!ax_skb)
return 0;

skb_put(ax_skb, size);
memcpy(ax_skb->data, skb->data + offset, size);
usbnet_skb_return(dev, ax_skb);
if (rx->size > skb->len - offset) {
remaining = rx->size - (skb->len - offset);
rx->size = skb->len - offset;
}

data = skb_put(rx->ax_skb, rx->size);
memcpy(data, skb->data + offset, rx->size);
if (!remaining)
usbnet_skb_return(dev, rx->ax_skb);

offset += (size + 1) & 0xfffe;
offset += (rx->size + 1) & 0xfffe;
rx->size = remaining;
}

if (skb->len != offset) {
netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
skb->len);
netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
skb->len, offset);
return 0;
}

return 1;
}

int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
{
struct asix_common_private *dp = dev->driver_priv;
struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;

return asix_rx_fixup_internal(dev, skb, rx);
}

struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags)
{
Expand Down
23 changes: 20 additions & 3 deletions trunk/drivers/net/usb/asix_devices.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size = 2048;
}

dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
if (!dev->driver_priv)
return -ENOMEM;

return 0;
}

void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
{
if (dev->driver_priv)
kfree(dev->driver_priv);
}

static const struct ethtool_ops ax88178_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = asix_get_link,
Expand Down Expand Up @@ -829,6 +839,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size = 2048;
}

dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
if (!dev->driver_priv)
return -ENOMEM;

return 0;
}

Expand Down Expand Up @@ -875,35 +889,38 @@ static const struct driver_info hawking_uf200_info = {
static const struct driver_info ax88772_info = {
.description = "ASIX AX88772 USB 2.0 Ethernet",
.bind = ax88772_bind,
.unbind = ax88772_unbind,
.status = asix_status,
.link_reset = ax88772_link_reset,
.reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};

static const struct driver_info ax88772b_info = {
.description = "ASIX AX88772B USB 2.0 Ethernet",
.bind = ax88772_bind,
.unbind = ax88772_unbind,
.status = asix_status,
.link_reset = ax88772_link_reset,
.reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
.data = FLAG_EEPROM_MAC,
};

static const struct driver_info ax88178_info = {
.description = "ASIX AX88178 USB 2.0 Ethernet",
.bind = ax88178_bind,
.unbind = ax88772_unbind,
.status = asix_status,
.link_reset = ax88178_link_reset,
.reset = ax88178_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
.rx_fixup = asix_rx_fixup,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};

Expand Down
11 changes: 10 additions & 1 deletion trunk/drivers/net/usb/ax88172a.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct ax88172a_private {
u16 phy_addr;
u16 oldmode;
int use_embdphy;
struct asix_rx_fixup_info rx_fixup_info;
};

/* MDIO read and write wrappers for phylib */
Expand Down Expand Up @@ -400,6 +401,14 @@ static int ax88172a_reset(struct usbnet *dev)

}

static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct ax88172a_private *dp = dev->driver_priv;
struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;

return asix_rx_fixup_internal(dev, skb, rx);
}

const struct driver_info ax88172a_info = {
.description = "ASIX AX88172A USB 2.0 Ethernet",
.bind = ax88172a_bind,
Expand All @@ -409,6 +418,6 @@ const struct driver_info ax88172a_info = {
.status = ax88172a_status,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup,
.rx_fixup = ax88172a_rx_fixup,
.tx_fixup = asix_tx_fixup,
};

0 comments on commit 65cec50

Please sign in to comment.