diff mbox

[v3,1/3] net/usb/r815x: replace USB buffer from stack to DMA-able

Message ID 1375172936-4145-1-git-send-email-hayeswang@realtek.com
State Superseded, archived
Delegated to: David Miller
Headers show

Commit Message

Hayes Wang July 30, 2013, 8:28 a.m. UTC
Allocate the transfer buffer in probe(), and use the buffer for
usb control transfer.

Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
 drivers/net/usb/r815x.c | 117 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 90 insertions(+), 27 deletions(-)

Comments

gregkh@linuxfoundation.org July 30, 2013, 1:58 p.m. UTC | #1
On Tue, Jul 30, 2013 at 04:28:54PM +0800, Hayes Wang wrote:
> Allocate the transfer buffer in probe(), and use the buffer for
> usb control transfer.
> 
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
> ---
>  drivers/net/usb/r815x.c | 117 +++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 90 insertions(+), 27 deletions(-)

In the future, you do not need to send drivers/net/usb/ patches to me,
netdev and the linux-usb mailing lists should be sufficient.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
gregkh@linuxfoundation.org July 30, 2013, 2 p.m. UTC | #2
On Tue, Jul 30, 2013 at 04:28:54PM +0800, Hayes Wang wrote:
> Allocate the transfer buffer in probe(), and use the buffer for
> usb control transfer.
> 
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
> ---
>  drivers/net/usb/r815x.c | 117 +++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 90 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
> index 8523922..89ad63f 100644
> --- a/drivers/net/usb/r815x.c
> +++ b/drivers/net/usb/r815x.c
> @@ -21,37 +21,52 @@
>  #define R815x_PHY_ID		32
>  #define REALTEK_VENDOR_ID	0x0bda
>  
> +struct r815x {
> +	struct mutex transfer_mutex;
> +	__le32 *transfer_buf;
> +};

Really?  Why not just allocate it the times you need to send the data?
Is it really all that often that you need to do this?

> -static int pla_read_word(struct usb_device *udev, u16 index)
> +static int pla_read_word(struct usbnet *dev, u16 index)
>  {
> -	int data, ret;
> +	struct r815x *tp = dev->driver_priv;
> +	struct usb_device *udev = dev->udev;
> +	int ret;
>  	u8 shift = index & 2;
> -	__le32 ocp_data;
> +	__le32 *tmp;
> +
> +	mutex_lock(&tp->transfer_mutex);
> +	tmp = tp->transfer_buf;
>  
>  	index &= ~3;
>  
>  	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
>  			      RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
> -			      index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
> -			      500);
> +			      index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);

This call is so slow, you can afford to make a call to kmalloc for the
data, as it sure just did for other structures it needed :)

So just do a kmalloc call for the data before this function, same for
your other patches in this series, no need for a lock for your "transfer
data" buffer, and a global one at all.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ming Lei July 30, 2013, 2:29 p.m. UTC | #3
On Tue, Jul 30, 2013 at 4:28 PM, Hayes Wang <hayeswang@realtek.com> wrote:
> Allocate the transfer buffer in probe(), and use the buffer for
> usb control transfer.

Looks this is a usbnet device, so suggest to use usbnet command APIs
(usbnet_read_cmd/usbnet_write_cmd) to do that, another advantage is
you can avoid to access runtime-suspended device from ethtool.


Thanks,
David Miller July 30, 2013, 6:33 p.m. UTC | #4
From: Greg KH <gregkh@linuxfoundation.org>
Date: Tue, 30 Jul 2013 07:00:59 -0700

> This call is so slow, you can afford to make a call to kmalloc for the
> data, as it sure just did for other structures it needed :)

I told him to implement things this way, to avoid calling kmalloc every
single register access.

Using kmalloc all the time makes the access fragile, since a badly timed
call during high memory pressure can fail.

I'd rather the potential failure happen at one time, probe time.

In any event, Ming Lei has suggested using usbnet_{read,write}_cmd()
instead, which sounds like a good solution to this problem.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches July 30, 2013, 6:41 p.m. UTC | #5
On Tue, 2013-07-30 at 11:33 -0700, David Miller wrote:
> From: Greg KH <gregkh@linuxfoundation.org>
> Date: Tue, 30 Jul 2013 07:00:59 -0700
> 
> > This call is so slow, you can afford to make a call to kmalloc for the
> > data, as it sure just did for other structures it needed :)
> 
> I told him to implement things this way, to avoid calling kmalloc every
> single register access.
> 
> Using kmalloc all the time makes the access fragile, since a badly timed
> call during high memory pressure can fail.
> 
> I'd rather the potential failure happen at one time, probe time.
> 
> In any event, Ming Lei has suggested using usbnet_{read,write}_cmd()
> instead, which sounds like a good solution to this problem.

Those do per-call allocs too.


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller July 30, 2013, 6:49 p.m. UTC | #6
From: Joe Perches <joe@perches.com>
Date: Tue, 30 Jul 2013 11:41:17 -0700

> On Tue, 2013-07-30 at 11:33 -0700, David Miller wrote:
>> From: Greg KH <gregkh@linuxfoundation.org>
>> Date: Tue, 30 Jul 2013 07:00:59 -0700
>> 
>> > This call is so slow, you can afford to make a call to kmalloc for the
>> > data, as it sure just did for other structures it needed :)
>> 
>> I told him to implement things this way, to avoid calling kmalloc every
>> single register access.
>> 
>> Using kmalloc all the time makes the access fragile, since a badly timed
>> call during high memory pressure can fail.
>> 
>> I'd rather the potential failure happen at one time, probe time.
>> 
>> In any event, Ming Lei has suggested using usbnet_{read,write}_cmd()
>> instead, which sounds like a good solution to this problem.
> 
> Those do per-call allocs too.

Sigh...  Ok I won't fight this any longer then :-)
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
gregkh@linuxfoundation.org July 30, 2013, 6:58 p.m. UTC | #7
On Tue, Jul 30, 2013 at 11:33:29AM -0700, David Miller wrote:
> From: Greg KH <gregkh@linuxfoundation.org>
> Date: Tue, 30 Jul 2013 07:00:59 -0700
> 
> > This call is so slow, you can afford to make a call to kmalloc for the
> > data, as it sure just did for other structures it needed :)
> 
> I told him to implement things this way, to avoid calling kmalloc every
> single register access.
> 
> Using kmalloc all the time makes the access fragile, since a badly timed
> call during high memory pressure can fail.
> 
> I'd rather the potential failure happen at one time, probe time.

I agree, but the call usb_control_message() also does a tiny kmalloc(),
and is _very_ slow and if you have high memory pressure, doing USB
messages like this is not what you want to do anyway (the host
controller does it's own allocations and the like as well.)

USB isn't "fast" like most normal networking physical layers :)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ming Lei July 31, 2013, 10:29 a.m. UTC | #8
On Wed, Jul 31, 2013 at 2:49 AM, David Miller <davem@davemloft.net> wrote:
> From: Joe Perches <joe@perches.com>
> Date: Tue, 30 Jul 2013 11:41:17 -0700
>
>> On Tue, 2013-07-30 at 11:33 -0700, David Miller wrote:
>>> From: Greg KH <gregkh@linuxfoundation.org>
>>> Date: Tue, 30 Jul 2013 07:00:59 -0700
>>>
>>> > This call is so slow, you can afford to make a call to kmalloc for the
>>> > data, as it sure just did for other structures it needed :)
>>>
>>> I told him to implement things this way, to avoid calling kmalloc every
>>> single register access.
>>>
>>> Using kmalloc all the time makes the access fragile, since a badly timed
>>> call during high memory pressure can fail.
>>>
>>> I'd rather the potential failure happen at one time, probe time.
>>>
>>> In any event, Ming Lei has suggested using usbnet_{read,write}_cmd()
>>> instead, which sounds like a good solution to this problem.
>>
>> Those do per-call allocs too.
>
> Sigh...  Ok I won't fight this any longer then :-)

It might not be a big deal because most of these commands are sent
during probe()/ethtool/... context, and not in tx/rx path.

Another choice is to reserve a big enough buffer during probe()
for read/write command, but one mutex is needed too for avoiding
concurrent calling.

Anyway, please call the command API to do such thing, so that we
can improve it easily in future.

Thanks,
diff mbox

Patch

diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
index 8523922..89ad63f 100644
--- a/drivers/net/usb/r815x.c
+++ b/drivers/net/usb/r815x.c
@@ -21,37 +21,52 @@ 
 #define R815x_PHY_ID		32
 #define REALTEK_VENDOR_ID	0x0bda
 
+struct r815x {
+	struct mutex transfer_mutex;
+	__le32 *transfer_buf;
+};
 
-static int pla_read_word(struct usb_device *udev, u16 index)
+static int pla_read_word(struct usbnet *dev, u16 index)
 {
-	int data, ret;
+	struct r815x *tp = dev->driver_priv;
+	struct usb_device *udev = dev->udev;
+	int ret;
 	u8 shift = index & 2;
-	__le32 ocp_data;
+	__le32 *tmp;
+
+	mutex_lock(&tp->transfer_mutex);
+	tmp = tp->transfer_buf;
 
 	index &= ~3;
 
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 			      RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-			      index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-			      500);
+			      index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
 	if (ret < 0)
-		return ret;
+		goto out2;
 
-	data = __le32_to_cpu(ocp_data);
-	data >>= (shift * 8);
-	data &= 0xffff;
+	ret = __le32_to_cpu(*tmp);
+	ret >>= (shift * 8);
+	ret &= 0xffff;
 
-	return data;
+out2:
+	mutex_unlock(&tp->transfer_mutex);
+	return ret;
 }
 
-static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
+static int pla_write_word(struct usbnet *dev, u16 index, u32 data)
 {
-	__le32 ocp_data;
+	struct r815x *tp = dev->driver_priv;
+	struct usb_device *udev = dev->udev;
+	__le32 *tmp;
 	u32 mask = 0xffff;
 	u16 byen = BYTE_EN_WORD;
 	u8 shift = index & 2;
 	int ret;
 
+	mutex_lock(&tp->transfer_mutex);
+	tmp = tp->transfer_buf;
+
 	data &= mask;
 
 	if (shift) {
@@ -63,19 +78,20 @@  static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 			      RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-			      index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-			      500);
+			      index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
 	if (ret < 0)
-		return ret;
+		goto out3;
 
-	data |= __le32_to_cpu(ocp_data) & ~mask;
-	ocp_data = __cpu_to_le32(data);
+	data |= __le32_to_cpu(*tmp) & ~mask;
+	*tmp = __cpu_to_le32(data);
 
 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			      RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-			      index, MCU_TYPE_PLA | byen, &ocp_data,
-			      sizeof(ocp_data), 500);
+			      index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
+			      500);
 
+out3:
+	mutex_unlock(&tp->transfer_mutex);
 	return ret;
 }
 
@@ -85,12 +101,12 @@  static int ocp_reg_read(struct usbnet *dev, u16 addr)
 	int ret;
 
 	ocp_base = addr & 0xf000;
-	ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
+	ret = pla_write_word(dev, OCP_BASE, ocp_base);
 	if (ret < 0)
 		goto out;
 
 	ocp_index = (addr & 0x0fff) | 0xb000;
-	ret = pla_read_word(dev->udev, ocp_index);
+	ret = pla_read_word(dev, ocp_index);
 
 out:
 	return ret;
@@ -102,12 +118,12 @@  static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
 	int ret;
 
 	ocp_base = addr & 0xf000;
-	ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
+	ret = pla_write_word(dev, OCP_BASE, ocp_base);
 	if (ret < 0)
 		goto out1;
 
 	ocp_index = (addr & 0x0fff) | 0xb000;
-	ret = pla_write_word(dev->udev, ocp_index, data);
+	ret = pla_write_word(dev, ocp_index, data);
 
 out1:
 	return ret;
@@ -134,12 +150,59 @@  void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
 	ocp_reg_write(dev, BASE_MII + reg * 2, val);
 }
 
-static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
+static int r815x_bind(struct usbnet *dev, struct usb_interface *intf)
 {
+	struct r815x *tp;
 	int status;
 
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL);
+	if (!tp)
+		return -ENOMEM;
+
+	memset(tp, 0, sizeof(*tp));
+
+	status = -ENOMEM;
+
+	tp->transfer_buf = kmalloc(sizeof(*tp->transfer_buf), GFP_KERNEL);
+	if (!tp->transfer_buf)
+		goto out1;
+
+	mutex_init (&tp->transfer_mutex);
+	dev->driver_priv = tp;
+
 	status = usbnet_cdc_bind(dev, intf);
 	if (status < 0)
+		goto out2;
+
+	return 0;
+
+out2:
+	kfree(tp->transfer_buf);
+out1:
+	kfree(tp);
+	return status;
+}
+
+static void r815x_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct r815x *tp = dev->driver_priv;
+
+	usbnet_cdc_unbind(dev, intf);
+
+	if (tp) {
+		if (tp->transfer_buf)
+			kfree(tp->transfer_buf);
+		kfree(tp);
+		dev->driver_priv = NULL;
+	}
+}
+
+static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int status;
+
+	status = r815x_bind(dev, intf);
+	if (status < 0)
 		return status;
 
 	dev->mii.dev = dev->net;
@@ -157,7 +220,7 @@  static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
 {
 	int status;
 
-	status = usbnet_cdc_bind(dev, intf);
+	status = r815x_bind(dev, intf);
 	if (status < 0)
 		return status;
 
@@ -176,7 +239,7 @@  static const struct driver_info r8152_info = {
 	.description =	"RTL8152 ECM Device",
 	.flags =	FLAG_ETHER | FLAG_POINTTOPOINT,
 	.bind =		r8152_bind,
-	.unbind =	usbnet_cdc_unbind,
+	.unbind =	r815x_unbind,
 	.status =	usbnet_cdc_status,
 	.manage_power =	usbnet_manage_power,
 };
@@ -185,7 +248,7 @@  static const struct driver_info r8153_info = {
 	.description =	"RTL8153 ECM Device",
 	.flags =	FLAG_ETHER | FLAG_POINTTOPOINT,
 	.bind =		r8153_bind,
-	.unbind =	usbnet_cdc_unbind,
+	.unbind =	r815x_unbind,
 	.status =	usbnet_cdc_status,
 	.manage_power =	usbnet_manage_power,
 };