From: Marek Vasut <marex@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 2/2] usb: eth: add Realtek RTL8152B/RTL8153 driver
Date: Tue, 1 Dec 2015 16:10:14 +0100 [thread overview]
Message-ID: <201512011610.14794.marex@denx.de> (raw)
In-Reply-To: <1448969081-21934-1-git-send-email-tedchen@realtek.com>
On Tuesday, December 01, 2015 at 12:24:41 PM, Ted Chen wrote:
> This patch adds driver support for the Realtek RTL8152B/RTL8153 USB
> network adapters.
Hi!
looks pretty good, just a few final nitpicks below.
> Signed-off-by: Ted Chen <tedchen@realtek.com>
> [swarren, fixed a few compiler warnings]
> [swarren, with permission, converted license header to SPDX]
> [swarren, removed printf() spew during probe()]
This changelog should be removed, really. It doesn't have to be in the commit
message, right ?
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
[...]
> +#include <common.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <usb.h>
> +#include <usb/lin_gadget_compat.h>
> +#include <linux/mii.h>
> +#include <linux/bitops.h>
> +#include "usb_ether.h"
> +#include "r8152.h"
> +
> +/* local vars */
> +static int curr_eth_dev; /* index for name of next device detected */
This $curr_eth_dev doesn't seem very DM friendly. Is this really needed?
> +struct r8152_dongle {
> + unsigned short vendor;
> + unsigned short product;
> +};
> +
> +static const struct r8152_dongle const r8152_dongles[] = {
> + /* Realtek */
> + { 0x0bda, 0x8050 },
> + { 0x0bda, 0x8152 },
> + { 0x0bda, 0x8153 },
> +
> + /* Samsung */
> + { 0x04e8, 0xa101 },
> +
> + /* Lenovo */
> + { 0x17ef, 0x304f },
> + { 0x17ef, 0x3052 },
> + { 0x17ef, 0x3054 },
> + { 0x17ef, 0x3057 },
> + { 0x17ef, 0x7205 },
> + { 0x17ef, 0x720a },
> + { 0x17ef, 0x720b },
> + { 0x17ef, 0x720c },
> +
> + /* TP-LINK */
> + { 0x2357, 0x0601 },
> +
> + /* Nvidia */
> + { 0x0955, 0x09ff },
> +
> + { 0x0000, 0x0000 } /* END - Do not remove */
> +};
> +
> +static
> +int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void
> *data) +{
> + int ret;
> +
> + ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
> + RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
> + value, index, data, size, 500);
> +
> + return ret;
> +}
> +
> +static
> +int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void
> *data) +{
> + int ret;
> +
> + ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
> + RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
> + value, index, data, size, 500);
> +
> + return ret;
> +}
> +
> +int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
> + void *data, u16 type)
> +{
> + u16 burst_size = 64;
> + int ret = 0;
int txsize;
> + /* both size and index must be 4 bytes align */
> + if ((size & 3) || !size || (index & 3) || !data)
> + return -EINVAL;
> +
> + if (index + size > 0xffff)
> + return -EINVAL;
> +
> + while (size) {
txsize = min(size, burst_size);
ret = get_registers(tp, index, type, txsize, data);
if (ret < 0)
break;
index += txsize;
data += txsize;
size =- txsize;
And you can drop this whole conditional statement. Right ?
> + if (size > burst_size) {
> + ret = get_registers(tp, index, type, burst_size, data);
> + if (ret < 0)
> + break;
> +
> + index += burst_size;
> + data += burst_size;
> + size -= burst_size;
> + } else {
> + ret = get_registers(tp, index, type, size, data);
> + if (ret < 0)
> + break;
> +
> + index += size;
> + data += size;
> + size = 0;
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
> + u16 size, void *data, u16 type)
> +{
> + int ret;
> + u16 byteen_start, byteen_end, byte_en_to_hw;
> + u16 burst_size = 512;
> +
> + /* both size and index must be 4 bytes align */
> + if ((size & 3) || !size || (index & 3) || !data)
> + return -EINVAL;
> +
> + if (index + size > 0xffff)
> + return -EINVAL;
> +
> + byteen_start = byteen & BYTE_EN_START_MASK;
> + byteen_end = byteen & BYTE_EN_END_MASK;
> +
> + byte_en_to_hw = byteen_start | (byteen_start << 4);
> + ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
> + if (ret < 0)
> + return ret;
> +
> + index += 4;
> + data += 4;
> + size -= 4;
> +
> + if (size) {
> + size -= 4;
> +
> + while (size) {
> + if (size > burst_size) {
> + ret = set_registers(tp, index,
> + type | BYTE_EN_DWORD,
> + burst_size, data);
> + if (ret < 0)
> + return ret;
> +
> + index += burst_size;
> + data += burst_size;
> + size -= burst_size;
> + } else {
> + ret = set_registers(tp, index,
> + type | BYTE_EN_DWORD,
> + size, data);
> + if (ret < 0)
> + return ret;
> +
> + index += size;
> + data += size;
> + size = 0;
> + break;
DTTO here
> + }
> + }
> +
> + byte_en_to_hw = byteen_end | (byteen_end >> 4);
> + ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return ret;
> +}
[...]
> +u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
> +{
> + u32 data;
> + __le32 tmp;
> + u8 shift = index & 2;
> +
> + index &= ~3;
> +
> + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
> +
> + data = __le32_to_cpu(tmp);
> + data >>= (shift * 8);
> + data &= 0xffff;
Can you please review the typecasts in the driver ? I don't think that a
lot of them are really necessary.
> + return (u16)data;
> +}
[...]
> +static void rtl8152_nic_reset(struct r8152 *tp)
> +{
> + int i;
> +
> + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, PLA_CR_RST);
> +
> + for (i = 0; i < 1000; i++) {
> + if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & PLA_CR_RST))
> + break;
> +
> + udelay(400);
> + }
So what exactly happens if this function fails 1000 times ? The NIC will not
be reset, but the code will proceed with whatever other actions?
> +}
[...]
> +static void rtl_disable(struct r8152 *tp)
> +{
> + u32 ocp_data;
> + int i;
> +
> + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
> + ocp_data &= ~RCR_ACPT_ALL;
> + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
> +
> + rxdy_gated_en(tp, true);
> +
> + for (i = 0; i < 1000; i++) {
You might want to pull this magic value, 1000, into a macro, since it's being
pretty repetitive in this driver. It seems to have some sort of significance.
> + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
> + if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
> + break;
> +
> + mdelay(2);
> + }
> +
> + for (i = 0; i < 1000; i++) {
> + if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
> + break;
> + mdelay(2);
> + }
> +
> + rtl8152_nic_reset(tp);
> +}
[...]
> +static int r8152_init(struct eth_device *eth, bd_t *bd)
> +{
> + struct ueth_data *dev = (struct ueth_data *)eth->priv;
ueth_data[SPACE]*dev please.
> + struct r8152 *tp = (struct r8152 *)dev->dev_priv;
> +
> + u8 speed;
> + int timeout = 0;
> +#define TIMEOUT_RESOLUTION 50 /* ms */
> +#define PHY_CONNECT_TIMEOUT 5000
I'd suggest to use const variable instead to leverage the typechecking.
> + int link_detected;
> +
> + debug("** %s()\n", __func__);
> +
> + do {
> + speed = rtl8152_get_speed(tp);
> +
> + link_detected = speed & LINK_STATUS;
> + if (!link_detected) {
> + if (timeout == 0)
> + printf("Waiting for Ethernet connection... ");
> + mdelay(TIMEOUT_RESOLUTION);
> + timeout += TIMEOUT_RESOLUTION;
> + }
> + } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
> + if (link_detected) {
> + tp->rtl_ops.enable(tp);
> +
> + if (timeout != 0)
> + printf("done.\n");
> + } else {
> + printf("unable to connect.\n");
> + }
> +
> + return 0;
> +}
> +
> +static int r8152_send(struct eth_device *eth, void *packet, int length)
> +{
> + struct ueth_data *dev = (struct ueth_data *)eth->priv;
> +
> + u32 opts1, opts2 = 0;
> +
> + int err;
> +
> + int actual_len;
> + unsigned char msg[PKTSIZE + sizeof(struct tx_desc)];
> + struct tx_desc *tx_desc = (struct tx_desc *)msg;
> +
> +#define USB_BULK_SEND_TIMEOUT 5000
DTTO here and in all the places where you use #define FOO in a function.
> + debug("** %s(), len %d\n", __func__, length);
> +
> + opts1 = length | TX_FS | TX_LS;
> +
> + tx_desc->opts2 = cpu_to_le32(opts2);
> + tx_desc->opts1 = cpu_to_le32(opts1);
> +
> + memcpy(msg + sizeof(struct tx_desc), (void *)packet, length);
> +
> + err = usb_bulk_msg(dev->pusb_dev,
> + usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
> + (void *)msg,
> + length + sizeof(struct tx_desc),
> + &actual_len,
> + USB_BULK_SEND_TIMEOUT);
> + debug("Tx: len = %zu, actual = %u, err = %d\n",
> + length + sizeof(struct tx_desc), actual_len, err);
> +
> + return err;
> +}
[...]
> +/* Probe to see if a new device is actually an realtek device */
> +int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum,
> + struct ueth_data *ss)
> +{
> + struct usb_interface *iface;
> + struct usb_interface_descriptor *iface_desc;
> + int ep_in_found = 0, ep_out_found = 0;
> + int i;
> +
> + struct r8152 *tp;
> +
> + /* let's examine the device now */
> + iface = &dev->config.if_desc[ifnum];
> + iface_desc = &dev->config.if_desc[ifnum].desc;
> +
> + for (i = 0; r8152_dongles[i].vendor != 0; i++) {
Maybe you can use ARRAY_SIZE() instead and avoid having 0x00 as a terminating
entry in the array . What do you think ?
> + if (dev->descriptor.idVendor == r8152_dongles[i].vendor &&
> + dev->descriptor.idProduct == r8152_dongles[i].product)
> + /* Found a supported dongle */
> + break;
> + }
> +
> + if (r8152_dongles[i].vendor == 0)
> + return 0;
> +
> + memset(ss, 0, sizeof(struct ueth_data));
> +
> + /* At this point, we know we've got a live one */
> + debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
> + dev->descriptor.idVendor, dev->descriptor.idProduct);
> +
> + /* Initialize the ueth_data structure with some useful info */
> + ss->ifnum = ifnum;
> + ss->pusb_dev = dev;
> + ss->subclass = iface_desc->bInterfaceSubClass;
> + ss->protocol = iface_desc->bInterfaceProtocol;
> +
> + /* alloc driver private */
> + ss->dev_priv = calloc(1, sizeof(struct r8152));
> +
> + if (!ss->dev_priv)
> + return 0;
> +
> + /*
> + * We are expecting a minimum of 3 endpoints - in, out (bulk), and
> + * int. We will ignore any others.
> + */
> + for (i = 0; i < iface_desc->bNumEndpoints; i++) {
> + /* is it an BULK endpoint? */
> + if ((iface->ep_desc[i].bmAttributes &
> + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
> + u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
> + if (ep_addr & USB_DIR_IN) {
> + if (!ep_in_found) {
You can probably rewrite it this way
if (!ep_in_found && (ep_addr & USB_DIR_IN)) {
do stuff ...
}
This might trim down the indentation, which looks really bad. But if it doesn't,
then don't worry about this.
> + ss->ep_in = ep_addr &
> + USB_ENDPOINT_NUMBER_MASK;
> + ep_in_found = 1;
> + }
> + } else {
> + if (!ep_out_found) {
> + ss->ep_out = ep_addr &
> + USB_ENDPOINT_NUMBER_MASK;
> + ep_out_found = 1;
> + }
> + }
> + }
> +
> + /* is it an interrupt endpoint? */
> + if ((iface->ep_desc[i].bmAttributes &
> + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
> + ss->ep_int = iface->ep_desc[i].bEndpointAddress &
> + USB_ENDPOINT_NUMBER_MASK;
> + ss->irqinterval = iface->ep_desc[i].bInterval;
> + }
> + }
[...]
next prev parent reply other threads:[~2015-12-01 15:10 UTC|newest]
Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-13 16:03 [U-Boot] [PATCH 1/2] checkpatch: ignore request to use ether_addr_copy() Stephen Warren
2015-11-13 16:03 ` [U-Boot] [PATCH 2/2] usb: eth: add Realtek RTL8152B/RTL8153 driver Stephen Warren
2015-11-14 1:13 ` Marek Vasut
2015-11-16 17:32 ` Stephen Warren
2015-11-17 7:18 ` Ted
2015-11-17 8:04 ` Marek Vasut
2015-11-19 6:07 ` Anand Moon
2015-11-19 16:51 ` Stephen Warren
2015-11-19 17:00 ` Lukasz Majewski
2015-11-19 17:00 ` Marek Vasut
2015-11-19 10:58 ` Anand Moon
2015-11-19 11:12 ` Marek Vasut
2015-11-19 12:49 ` Anand Moon
2015-11-19 13:12 ` Marek Vasut
2015-11-20 17:35 ` Simon Glass
2015-11-20 17:38 ` Marek Vasut
2015-11-21 4:10 ` Anand Moon
2015-11-22 17:12 ` Stephen Warren
2015-11-22 19:25 ` Anand Moon
2015-11-21 7:27 ` Stephen Warren
2015-11-21 16:50 ` Simon Glass
2015-11-22 17:09 ` Stephen Warren
2015-11-23 3:09 ` Simon Glass
2015-11-23 17:16 ` Stephen Warren
2015-11-25 5:30 ` [U-Boot] [PATCH v2 " Ted Chen
2015-11-25 9:09 ` Anand Moon
2015-11-26 16:58 ` Marek Vasut
2015-11-30 22:07 ` Joe Hershberger
2015-12-01 11:24 ` [U-Boot] [PATCH v3 " Ted Chen
2015-12-01 15:10 ` Marek Vasut [this message]
2015-12-01 16:31 ` Stephen Warren
2015-12-01 17:11 ` Marek Vasut
2015-12-01 16:32 ` Simon Glass
2016-01-13 18:27 ` Stephen Warren
2016-01-14 4:37 ` [U-Boot] [PATCH v4 2/2] usb: eth: add Realtek RTL8152B/RTL8153 DRIVER Ted Chen
2016-01-14 4:42 ` Marek Vasut
2016-01-14 5:22 ` Ted Chen
2016-01-14 5:37 ` Marek Vasut
2016-01-20 6:24 ` [U-Boot] [PATCH v5 " Ted Chen
2016-01-20 13:08 ` Marek Vasut
2016-01-20 16:52 ` Stephen Warren
2016-01-20 20:10 ` Anand Moon
2016-01-20 20:34 ` Marek Vasut
2016-01-21 8:55 ` Anand Moon
2016-01-21 10:12 ` Marek Vasut
2016-01-22 19:50 ` Joe Hershberger
2016-01-22 20:00 ` Marek Vasut
2016-01-22 20:41 ` Joe Hershberger
2016-01-23 0:42 ` Marek Vasut
2016-01-23 15:23 ` Marek Vasut
2016-01-23 18:55 ` Anand Moon
2016-01-23 19:38 ` Marek Vasut
2016-01-25 3:42 ` Ted
2016-01-25 3:47 ` Marek Vasut
2015-11-14 0:56 ` [U-Boot] [PATCH 1/2] checkpatch: ignore request to use ether_addr_copy() Marek Vasut
2015-11-23 23:36 ` Joe Hershberger
2015-12-15 23:34 ` Stephen Warren
2015-12-15 23:41 ` Joe Hershberger
[not found] ` <56969621.30204@wwwdotorg.org>
2016-01-20 20:47 ` Stephen Warren
2016-01-20 21:00 ` Tom Rini
2016-01-20 21:04 ` Stephen Warren
2016-01-21 1:22 ` Tom Rini
2016-01-21 4:09 ` Joe Hershberger
2016-01-25 21:28 ` [U-Boot] [U-Boot, " Tom Rini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201512011610.14794.marex@denx.de \
--to=marex@denx.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.