mirror of https://gitee.com/openkylin/linux.git
greybus: es2: Add a new bulk in endpoint for APBridgeA RPC
Add a new bulk in endpoint in order to get RPC status from APbridgeA without to have to poll on control endpoint. So the new endpoint layout is: EP0: control EP EP1 and EP2: muxed endpoints (bulk in and out) EP3 to EP14: direct muxed endpoints (bulk in and out) EP15: ARPC bulk in endpoint Note: This patch is allocating ARPC URBs but does nothing with them. The following patch will use them. Testing Done: Tested with an APBridgeA enumerating 16 endpoints. Kernel doesn't print Not enough endpoints found in device, aborting! Signed-off-by: Alexandre Bailon <abailon@baylibre.com> Reviewed-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Alex Elder <elder@linaro.org>
This commit is contained in:
parent
576bffb5a8
commit
9d9d3777a9
|
@ -25,6 +25,9 @@
|
||||||
/* Memory sizes for the buffers sent to/from the ES2 controller */
|
/* Memory sizes for the buffers sent to/from the ES2 controller */
|
||||||
#define ES2_GBUF_MSG_SIZE_MAX 2048
|
#define ES2_GBUF_MSG_SIZE_MAX 2048
|
||||||
|
|
||||||
|
/* Memory sizes for the ARPC buffers */
|
||||||
|
#define ARPC_IN_SIZE_MAX 128
|
||||||
|
|
||||||
static const struct usb_device_id id_table[] = {
|
static const struct usb_device_id id_table[] = {
|
||||||
{ USB_DEVICE(0x18d1, 0x1eaf) },
|
{ USB_DEVICE(0x18d1, 0x1eaf) },
|
||||||
{ },
|
{ },
|
||||||
|
@ -36,6 +39,12 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
||||||
/* Number of bulk in and bulk out couple */
|
/* Number of bulk in and bulk out couple */
|
||||||
#define NUM_BULKS 7
|
#define NUM_BULKS 7
|
||||||
|
|
||||||
|
/* Expected number of bulk out endpoints */
|
||||||
|
#define NUM_BULKS_OUT NUM_BULKS
|
||||||
|
|
||||||
|
/* Expected number of bulk in endpoints (including ARPC endpoint) */
|
||||||
|
#define NUM_BULKS_IN (NUM_BULKS + 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of CPort IN urbs in flight at any point in time.
|
* Number of CPort IN urbs in flight at any point in time.
|
||||||
* Adjust if we are having stalls in the USB buffer due to not enough urbs in
|
* Adjust if we are having stalls in the USB buffer due to not enough urbs in
|
||||||
|
@ -48,6 +57,11 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
||||||
*/
|
*/
|
||||||
#define NUM_CPORT_OUT_URB (8 * NUM_BULKS)
|
#define NUM_CPORT_OUT_URB (8 * NUM_BULKS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of ARPC in urbs in flight at any point in time.
|
||||||
|
*/
|
||||||
|
#define NUM_ARPC_IN_URB 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @endpoint: bulk in endpoint for CPort data
|
* @endpoint: bulk in endpoint for CPort data
|
||||||
* @urb: array of urbs for the CPort in messages
|
* @urb: array of urbs for the CPort in messages
|
||||||
|
@ -85,6 +99,9 @@ struct es2_cport_out {
|
||||||
* @apb_log_dentry: file system entry for the log file interface
|
* @apb_log_dentry: file system entry for the log file interface
|
||||||
* @apb_log_enable_dentry: file system entry for enabling logging
|
* @apb_log_enable_dentry: file system entry for enabling logging
|
||||||
* @apb_log_fifo: kernel FIFO to carry logged data
|
* @apb_log_fifo: kernel FIFO to carry logged data
|
||||||
|
* @arpc_urb: array of urbs for the ARPC in messages
|
||||||
|
* @arpc_buffer: array of buffers for the @arpc_urb urbs
|
||||||
|
* @arpc_endpoint_in: bulk in endpoint for APBridgeA RPC
|
||||||
*/
|
*/
|
||||||
struct es2_ap_dev {
|
struct es2_ap_dev {
|
||||||
struct usb_device *usb_dev;
|
struct usb_device *usb_dev;
|
||||||
|
@ -106,6 +123,10 @@ struct es2_ap_dev {
|
||||||
struct dentry *apb_log_dentry;
|
struct dentry *apb_log_dentry;
|
||||||
struct dentry *apb_log_enable_dentry;
|
struct dentry *apb_log_enable_dentry;
|
||||||
DECLARE_KFIFO(apb_log_fifo, char, APB1_LOG_SIZE);
|
DECLARE_KFIFO(apb_log_fifo, char, APB1_LOG_SIZE);
|
||||||
|
|
||||||
|
__u8 arpc_endpoint_in;
|
||||||
|
struct urb *arpc_urb[NUM_ARPC_IN_URB];
|
||||||
|
u8 *arpc_buffer[NUM_ARPC_IN_URB];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -344,6 +365,45 @@ static void es2_cport_in_disable(struct es2_ap_dev *es2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int es2_arpc_in_enable(struct es2_ap_dev *es2)
|
||||||
|
{
|
||||||
|
struct urb *urb;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
|
||||||
|
urb = es2->arpc_urb[i];
|
||||||
|
|
||||||
|
ret = usb_submit_urb(urb, GFP_KERNEL);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&es2->usb_dev->dev,
|
||||||
|
"failed to submit arpc in-urb: %d\n", ret);
|
||||||
|
goto err_kill_urbs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_kill_urbs:
|
||||||
|
for (--i; i >= 0; --i) {
|
||||||
|
urb = es2->arpc_urb[i];
|
||||||
|
usb_kill_urb(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void es2_arpc_in_disable(struct es2_ap_dev *es2)
|
||||||
|
{
|
||||||
|
struct urb *urb;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
|
||||||
|
urb = es2->arpc_urb[i];
|
||||||
|
usb_kill_urb(urb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct urb *next_free_urb(struct es2_ap_dev *es2, gfp_t gfp_mask)
|
static struct urb *next_free_urb(struct es2_ap_dev *es2, gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
struct urb *urb = NULL;
|
struct urb *urb = NULL;
|
||||||
|
@ -899,6 +959,16 @@ static void es2_destroy(struct es2_ap_dev *es2)
|
||||||
es2->cport_out_urb_busy[i] = false; /* just to be anal */
|
es2->cport_out_urb_busy[i] = false; /* just to be anal */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
|
||||||
|
struct urb *urb = es2->arpc_urb[i];
|
||||||
|
|
||||||
|
if (!urb)
|
||||||
|
break;
|
||||||
|
usb_free_urb(urb);
|
||||||
|
kfree(es2->arpc_buffer[i]);
|
||||||
|
es2->arpc_buffer[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (bulk_in = 0; bulk_in < NUM_BULKS; bulk_in++) {
|
for (bulk_in = 0; bulk_in < NUM_BULKS; bulk_in++) {
|
||||||
struct es2_cport_in *cport_in = &es2->cport_in[bulk_in];
|
struct es2_cport_in *cport_in = &es2->cport_in[bulk_in];
|
||||||
|
|
||||||
|
@ -991,6 +1061,31 @@ static void cport_out_callback(struct urb *urb)
|
||||||
free_urb(es2, urb);
|
free_urb(es2, urb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void arpc_in_callback(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct device *dev = &urb->dev->dev;
|
||||||
|
int status = check_urb_status(urb);
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
if ((status == -EAGAIN) || (status == -EPROTO))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* The urb is being unlinked */
|
||||||
|
if (status == -ENOENT || status == -ESHUTDOWN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_err(dev, "arpc in-urb error %d (dropped)\n", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
/* put our urb back in the request pool */
|
||||||
|
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
|
if (retval)
|
||||||
|
dev_err(dev, "failed to resubmit arpc in-urb: %d\n", retval);
|
||||||
|
}
|
||||||
|
|
||||||
#define APB1_LOG_MSG_SIZE 64
|
#define APB1_LOG_MSG_SIZE 64
|
||||||
static void apb_log_get(struct es2_ap_dev *es2, char *buf)
|
static void apb_log_get(struct es2_ap_dev *es2, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -1225,8 +1320,13 @@ static int ap_probe(struct usb_interface *interface,
|
||||||
endpoint = &iface_desc->endpoint[i].desc;
|
endpoint = &iface_desc->endpoint[i].desc;
|
||||||
|
|
||||||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||||
es2->cport_in[bulk_in++].endpoint =
|
if (bulk_in < NUM_BULKS)
|
||||||
endpoint->bEndpointAddress;
|
es2->cport_in[bulk_in].endpoint =
|
||||||
|
endpoint->bEndpointAddress;
|
||||||
|
else
|
||||||
|
es2->arpc_endpoint_in =
|
||||||
|
endpoint->bEndpointAddress;
|
||||||
|
bulk_in++;
|
||||||
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||||
es2->cport_out[bulk_out++].endpoint =
|
es2->cport_out[bulk_out++].endpoint =
|
||||||
endpoint->bEndpointAddress;
|
endpoint->bEndpointAddress;
|
||||||
|
@ -1236,7 +1336,7 @@ static int ap_probe(struct usb_interface *interface,
|
||||||
endpoint->bEndpointAddress);
|
endpoint->bEndpointAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bulk_in != NUM_BULKS || bulk_out != NUM_BULKS) {
|
if (bulk_in != NUM_BULKS_IN || bulk_out != NUM_BULKS_OUT) {
|
||||||
dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
|
dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1271,6 +1371,32 @@ static int ap_probe(struct usb_interface *interface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate buffers for ARPC in messages */
|
||||||
|
for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
|
||||||
|
struct urb *urb;
|
||||||
|
u8 *buffer;
|
||||||
|
|
||||||
|
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!urb) {
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
buffer = kmalloc(ARPC_IN_SIZE_MAX, GFP_KERNEL);
|
||||||
|
if (!buffer) {
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_fill_bulk_urb(urb, udev,
|
||||||
|
usb_rcvbulkpipe(udev,
|
||||||
|
es2->arpc_endpoint_in),
|
||||||
|
buffer, ARPC_IN_SIZE_MAX,
|
||||||
|
arpc_in_callback, es2);
|
||||||
|
|
||||||
|
es2->arpc_urb[i] = urb;
|
||||||
|
es2->arpc_buffer[i] = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate urbs for our CPort OUT messages */
|
/* Allocate urbs for our CPort OUT messages */
|
||||||
for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
|
for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
|
@ -1291,9 +1417,12 @@ static int ap_probe(struct usb_interface *interface,
|
||||||
gb_debugfs_get(), es2,
|
gb_debugfs_get(), es2,
|
||||||
&apb_log_enable_fops);
|
&apb_log_enable_fops);
|
||||||
|
|
||||||
|
if (es2_arpc_in_enable(es2))
|
||||||
|
goto error;
|
||||||
|
|
||||||
retval = gb_hd_add(hd);
|
retval = gb_hd_add(hd);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto error;
|
goto err_disable_arpc_in;
|
||||||
|
|
||||||
for (i = 0; i < NUM_BULKS; ++i) {
|
for (i = 0; i < NUM_BULKS; ++i) {
|
||||||
retval = es2_cport_in_enable(es2, &es2->cport_in[i]);
|
retval = es2_cport_in_enable(es2, &es2->cport_in[i]);
|
||||||
|
@ -1307,6 +1436,8 @@ static int ap_probe(struct usb_interface *interface,
|
||||||
for (--i; i >= 0; --i)
|
for (--i; i >= 0; --i)
|
||||||
es2_cport_in_disable(es2, &es2->cport_in[i]);
|
es2_cport_in_disable(es2, &es2->cport_in[i]);
|
||||||
gb_hd_del(hd);
|
gb_hd_del(hd);
|
||||||
|
err_disable_arpc_in:
|
||||||
|
es2_arpc_in_disable(es2);
|
||||||
error:
|
error:
|
||||||
es2_destroy(es2);
|
es2_destroy(es2);
|
||||||
|
|
||||||
|
@ -1322,6 +1453,7 @@ static void ap_disconnect(struct usb_interface *interface)
|
||||||
|
|
||||||
for (i = 0; i < NUM_BULKS; ++i)
|
for (i = 0; i < NUM_BULKS; ++i)
|
||||||
es2_cport_in_disable(es2, &es2->cport_in[i]);
|
es2_cport_in_disable(es2, &es2->cport_in[i]);
|
||||||
|
es2_arpc_in_disable(es2);
|
||||||
|
|
||||||
es2_destroy(es2);
|
es2_destroy(es2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue