@@ -362,6 +362,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
if (ret)
goto out;
+ /* Set Rx urb size */
+ dev->rx_urb_size = URB_SIZE;
+
/* Set TX needed headroom & tailroom */
dev->net->needed_headroom += AQ_TX_HEADER_SIZE;
dev->net->needed_tailroom += AQ_TX_HEADER_SIZE;
@@ -621,6 +624,8 @@ static int aqc111_reset(struct usbnet *dev)
usb_speed = dev->udev->speed;
+ dev->rx_urb_size = URB_SIZE;
+
if (usb_device_no_sg_constraint(dev->udev))
dev->can_dma_sg = 1;
@@ -708,6 +713,100 @@ static int aqc111_stop(struct usbnet *dev)
return 0;
}
+static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ struct sk_buff *new_skb = NULL;
+ u32 skb_len = 0;
+ u32 desc_offset = 0; /*RX Header Offset*/
+ u32 start_of_descs = 0;
+ u16 pkt_count = 0;
+ u32 pkt_total_offset = 0;
+ struct aq_rx_packet_desc *pkt_desc = NULL;
+ struct aq_rx_desc_header desc_hdr;
+
+ if (!skb)
+ goto err;
+
+ if (skb->len == 0)
+ goto err;
+
+ skb_len = skb->len;
+ /* RX Offset Header */
+ skb_trim(skb, skb->len - sizeof(struct aq_rx_desc_header));
+ memcpy(&desc_hdr, skb_tail_pointer(skb),
+ sizeof(struct aq_rx_desc_header));
+ le64_to_cpus(&desc_hdr);
+
+ /* Check these packets */
+ desc_offset = (u32)desc_hdr.desc_offset;
+ pkt_count = desc_hdr.pkt_count;
+ start_of_descs = skb_len - ((pkt_count + 1) *
+ sizeof(struct aq_rx_desc_header));
+
+ /* self check descs position */
+ if (start_of_descs != desc_offset)
+ goto err;
+
+ /* self check desc_offset from header*/
+ if (desc_offset >= skb_len)
+ goto err;
+
+ if (pkt_count == 0)
+ goto err;
+
+ /* Get the first RX packet header */
+ pkt_desc = (struct aq_rx_packet_desc *)(skb->data + desc_offset);
+
+ while (pkt_count--) {
+ u32 pkt_len = (u32)(pkt_desc->length & 0x7FFF);
+ u32 pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8);
+
+ le64_to_cpus(pkt_desc);
+
+ pkt_total_offset += pkt_len_with_padd;
+ if (pkt_total_offset > desc_offset ||
+ (pkt_count == 0 && pkt_total_offset != desc_offset)) {
+ goto err;
+ }
+
+ if (pkt_desc->drop || !pkt_desc->rx_ok ||
+ pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) {
+ skb_pull(skb, pkt_len_with_padd);
+ /* Next RX Packet Header */
+ pkt_desc++;
+ continue;
+ }
+
+ /* Clone SKB */
+ new_skb = skb_clone(skb, GFP_ATOMIC);
+
+ if (!new_skb)
+ goto err;
+
+ new_skb->len = pkt_len;
+ skb_pull(new_skb, AQ_RX_HW_PAD);
+ skb_set_tail_pointer(new_skb, new_skb->len);
+
+ new_skb->truesize = new_skb->len + sizeof(struct sk_buff);
+
+ usbnet_skb_return(dev, new_skb);
+ if (pkt_count == 0)
+ break;
+
+ skb_pull(skb, pkt_len_with_padd);
+
+ /* Next RX Packet Header */
+ pkt_desc++;
+
+ new_skb = NULL;
+ }
+
+ return 1;
+
+err:
+ return 0;
+}
+
static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags)
{
@@ -769,6 +868,7 @@ static const struct driver_info aqc111_info = {
.stop = aqc111_stop,
.flags = FLAG_ETHER | FLAG_FRAMING_AX |
FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET,
+ .rx_fixup = aqc111_rx_fixup,
.tx_fixup = aqc111_tx_fixup,
};
@@ -10,6 +10,8 @@
#ifndef __LINUX_USBNET_AQC111_H
#define __LINUX_USBNET_AQC111_H
+#define URB_SIZE (1024 * 62)
+
#define AQ_ACCESS_MAC 0x01
#define AQ_FLASH_PARAMETERS 0x20
#define AQ_PHY_POWER 0x31
@@ -228,6 +230,8 @@ struct aqc111_int_data {
#define AQ_INT_SPEED_1G 0x11
#define AQ_INT_SPEED_100M 0x13
+#define AQ_RX_HW_PAD 0x02
+
struct aq_tx_packet_desc {
struct {
u32 length:21;
@@ -246,6 +250,41 @@ struct aq_tx_packet_desc {
#define AQ_TX_HEADER_SIZE sizeof(struct aq_tx_packet_desc)
+struct aq_rx_packet_desc {
+ struct {
+ u16 l4_err:1;
+ u16 l3_err:1;
+ u16 l4_pkt_type:3;
+ u16 l3_pkt_type:2;
+ u16 ce:1;
+ u16 tco_match:1;
+ u16 node_id_match:1;
+ u16 vlan_ind : 1;
+ u16 rx_ok:1;
+ u16 reserved1 : 3;
+ u16 bmc:1;
+ };
+ struct {
+ u16 length:15;
+ u16 drop:1;
+ };
+ u16 vlan_tag;
+ struct {
+ u8 wuf_detect:1;
+ u8 wuf_wake:1;
+ u8 wuf_ind:6;
+ u8 reserved2:8;
+ };
+};
+
+struct aq_rx_desc_header {
+ struct {
+ u32 pkt_count:13;
+ u32 desc_offset:19;
+ };
+ u32 rx_throughput;
+};
+
static struct {
unsigned char ctrl;
unsigned char timer_l;