This patch is against the current torvalds git tree with usb-usbnet-gfp_flags-fix.patch and David Brownell's nine usbnet modularization patches applied.

I found that the modularization patches broke the ax88772 framing code. The rx urb's were not being sized large enough to hold the maximum burst the ax88772 device might send. After some off-line discussions with David-B, we concluded the best solution was to add a rx_urb_size field in the usbnet structure that allows a mini-drivers to specify the required urb size.

I also fixed the mdio byte order problems recently discussed on the list. This was causing media negotiation problems for a user, "Magnus", running on a PPC processor. I adopted the endian conversion wrapper approach.

I replaced some of the ax88772 framing code that caused unaligned access faults on architectures that are picky about that (mips, for one). There are still more of these lurking (e.g. when multiple eth frames are received in a single usb bulk transfer), but this catches the major cause of those faults. The remaining cases are less common, and messier to fix, so I'll save that for a future patch.

The asix link_reset code was looking only at the link partner capabilities. This failed when speeds were forced with ethtool. This was a bug I introduced in an earlier suggested modification to support pause frame flow control. I've corrected this by using both the link partner and advertised capabilities and mii_nway_result to determine the current media state.

Please review and let me know if there is anything I can improve. Also, if this is too much for one patch, and you'd rather see the changes separated, let me know that too. This is a precursor to my changes to add support for the airlink ax88178 based gige adapter to the asix usbnet minidriver.

--Jamie

diff -ur linux-2.6/drivers/usb/net/asix.c linux-2.6-new/drivers/usb/net/asix.c
--- linux-2.6/drivers/usb/net/asix.c	2005-08-18 22:38:39.000000000 -0600
+++ linux-2.6-new/drivers/usb/net/asix.c	2005-08-18 22:54:16.000000000 -0600
@@ -281,6 +281,12 @@
 	return res & 0xffff;
 }
 
+/* same as above, but converts resulting value to cpu byte order */
+static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
+{
+	return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc));
+}
+
 static void
 ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
 {
@@ -294,14 +300,25 @@
 	ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
 }
 
+/* same as above, but converts new value to le16 byte order before writing */
+static void
+ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+}
+
 static int ax88172_link_reset(struct usbnet *dev)
 {
 	u16 lpa;
+	u16 adv;
+	u16 res;
 	u8 mode;
 
 	mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
-	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
-	if (lpa & LPA_DUPLEX)
+	lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+	adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+	res = mii_nway_result(lpa|adv);
+	if (res & LPA_DUPLEX)
 		mode |= AX_MEDIUM_FULL_DUPLEX;
 	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
 
@@ -488,16 +505,11 @@
 	dev->net->set_multicast_list = ax8817x_set_multicast;
 	dev->net->ethtool_ops = &ax8817x_ethtool_ops;
 
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
 		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
 	mii_nway_restart(&dev->mii);
 
-	if (dev->driver_info->flags & FLAG_FRAMING_AX) {
-		/* REVISIT:  adjust hard_header_len too */
-		dev->hard_mtu = 2048;
-	}
-
 	return 0;
 out2:
 	kfree(buf);
@@ -634,8 +646,8 @@
 	dev->net->set_multicast_list = ax8817x_set_multicast;
 	dev->net->ethtool_ops = &ax88772_ethtool_ops;
 
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
 			ADVERTISE_ALL | ADVERTISE_CSMA);
 	mii_nway_restart(&dev->mii);
 
@@ -667,6 +679,13 @@
 
 	kfree(buf);
 
+	/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+	if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+		/* hard_mtu  is still the default - the device does not support 
+		   jumbo eth frames */
+		dev->rx_urb_size = 2048; 
+	}
+
 	return 0;
 
 out2:
@@ -677,24 +696,26 @@
 
 static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
-	u32 *header;
+	u8  *head;
+	u32  header;
 	char *packet;
 	struct sk_buff *ax_skb;
 	u16 size;
 
-	header = (u32 *) skb->data;
-	le32_to_cpus(header);
-	packet = (char *)(header + 1);
+	head = (u8 *) skb->data;
+	memcpy(&header, head, sizeof(header));
+	le32_to_cpus(&header);
+	packet = head + sizeof(header);
 
 	skb_pull(skb, 4);
 
 	while (skb->len > 0) {
-		if ((short)(*header & 0x0000ffff) !=
-		    ~((short)((*header & 0xffff0000) >> 16))) {
+		if ((short)(header & 0x0000ffff) !=
+		    ~((short)((header & 0xffff0000) >> 16))) {
 			devdbg(dev,"header length data is error");
 		}
 		/* get the packet length */
-		size = (u16) (*header & 0x0000ffff);
+		size = (u16) (header & 0x0000ffff);
 
 		if ((skb->len) - ((size + 1) & 0xfffe) == 0)
 			return 2;
@@ -717,9 +738,10 @@
 		if (skb->len == 0)
 			break;
 
-		header = (u32 *) skb->data;
-		le32_to_cpus(header);
-		packet = (char *)(header + 1);
+		head = (u8 *) skb->data;
+		memcpy(&header, head, sizeof(header));
+		le32_to_cpus(&header);
+		packet = head + sizeof(header);
 		skb_pull(skb, 4);
 	}
 
@@ -736,8 +758,8 @@
 	int padlen;
 	int headroom = skb_headroom(skb);
 	int tailroom = skb_tailroom(skb);
-	u32 *packet_len;
-	u32 *padbytes_ptr;
+	u32 packet_len;
+	u32 padbytes = 0xffff0000;
 
 	padlen = ((skb->len + 4) % 512) ? 0 : 4;
 
@@ -756,15 +778,13 @@
 			return NULL;
 	}
 
-	packet_len = (u32 *) skb_push(skb, 4);
-
-	packet_len = (u32 *) skb->data;
-	*packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+	skb_push(skb, 4);
+	packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+	memcpy(skb->data, &packet_len, sizeof(packet_len));
 
 	if ((skb->len % 512) == 0) {
-		padbytes_ptr = (u32 *) skb->tail;
-		*padbytes_ptr = 0xffff0000;
-		skb_put(skb, padlen);
+		memcpy( skb->tail, &padbytes, sizeof(padbytes));
+		skb_put(skb, sizeof(padbytes));
 	}
 	return skb;
 }
@@ -772,14 +792,18 @@
 static int ax88772_link_reset(struct usbnet *dev)
 {
 	u16 lpa;
+	u16 adv;
+	u16 res;
 	u16 mode;
 
 	mode = AX88772_MEDIUM_DEFAULT;
-	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
+	lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+	adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+	res = mii_nway_result(lpa|adv);
 
-	if ((lpa & LPA_DUPLEX) == 0)
+	if ((res & LPA_DUPLEX) == 0)
 		mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
-	if ((lpa & LPA_100) == 0)
+	if ((res & LPA_100) == 0)
 		mode &= ~AX88772_MEDIUM_100MB;
 	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
 
diff -ur linux-2.6/drivers/usb/net/usbnet.c linux-2.6-new/drivers/usb/net/usbnet.c
--- linux-2.6/drivers/usb/net/usbnet.c	2005-08-18 22:39:38.000000000 -0600
+++ linux-2.6-new/drivers/usb/net/usbnet.c	2005-08-18 22:54:16.000000000 -0600
@@ -287,10 +287,12 @@
 	struct skb_data		*entry;
 	int			retval = 0;
 	unsigned long		lockflags;
-	size_t			size;
+	size_t			size = dev->rx_urb_size;
 
-	size = max(dev->net->hard_header_len + dev->net->mtu,
-			(unsigned)ETH_FRAME_LEN);
+	// Set the urb size to the default, if the mini driver didn't
+	if (size==0)
+		size = max(dev->net->hard_header_len + dev->net->mtu,
+			   (unsigned)ETH_FRAME_LEN);
 	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
 		if (netif_msg_rx_err (dev))
 			devdbg (dev, "no rx skb");
@@ -1071,7 +1073,7 @@
 	strcpy (net->name, "usb%d");
 	memcpy (net->dev_addr, node_id, sizeof node_id);
 	dev->hard_mtu = net->mtu + net->hard_header_len;
-
+	dev->rx_urb_size = 0;	/* filled in later */
 #if 0
 // dma_supported() is deeply broken on almost all architectures
 	// possible with some EHCI controllers
diff -ur linux-2.6/drivers/usb/net/usbnet.h linux-2.6-new/drivers/usb/net/usbnet.h
--- linux-2.6/drivers/usb/net/usbnet.h	2005-08-18 22:39:18.000000000 -0600
+++ linux-2.6-new/drivers/usb/net/usbnet.h	2005-08-18 22:54:16.000000000 -0600
@@ -45,6 +45,7 @@
 	unsigned long		data [5];
 	u32			xid;
 	u32			hard_mtu;	/* count any extra framing */
+	size_t		        rx_urb_size;    /* size for rx urbs  */
 	struct mii_if_info	mii;
 
 	/* various kinds of pending driver work */

Reply via email to