summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Yen <howardyen@google.com>2021-06-30 15:03:21 +0800
committerHoward Yen <howardyen@google.com>2021-07-09 02:53:46 +0000
commita3e1882fe92c403777328ecca4bdd8edd3bcc65a (patch)
tree774c6afb66a0d1b6f37c9996dd053e43f360e7fd
parent8bdcf7e55ea861c753ea5eae5993837caae0a59b (diff)
downloadaoc-a3e1882fe92c403777328ecca4bdd8edd3bcc65a.tar.gz
aoc: usb: use DRAM for usb audio offload
Bug: 192326094 Test: build and boot pass Change-Id: Ie3d333a0494f0131fffd0e013a17941b06ab0f1c Signed-off-by: Howard Yen <howardyen@google.com>
-rw-r--r--usb/aoc_usb.h5
-rw-r--r--usb/aoc_usb_dev.c72
-rw-r--r--usb/xhci_hooks_impl_whi.c97
3 files changed, 156 insertions, 18 deletions
diff --git a/usb/aoc_usb.h b/usb/aoc_usb.h
index b3115bd..89bfb52 100644
--- a/usb/aoc_usb.h
+++ b/usb/aoc_usb.h
@@ -23,9 +23,11 @@ extern bool aoc_usb_probe_done;
enum aoc_usb_msg {
SYNC_DEVICE_CONTEXT,
GET_DCBAA_PTR,
+ SET_DCBAA_PTR,
GET_TR_DEQUEUE_PTR,
SETUP_DONE,
GET_ISOC_TR_INFO,
+ SET_ISOC_TR_INFO,
SYNC_CONN_STAT
};
@@ -36,7 +38,8 @@ enum aoc_usb_state {
enum usb_offload_op_mode {
USB_OFFLOAD_STOP,
- USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY
+ USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY,
+ USB_OFFLOAD_DRAM
};
enum usb_recover_state {
diff --git a/usb/aoc_usb_dev.c b/usb/aoc_usb_dev.c
index 9e331e7..ccfae9c 100644
--- a/usb/aoc_usb_dev.c
+++ b/usb/aoc_usb_dev.c
@@ -44,6 +44,8 @@ static ssize_t aoc_usb_send_command(struct aoc_usb_drvdata *drvdata,
if (aoc_service_flush_read_data(adev))
dev_err(&drvdata->adev->dev ,"Previous response left in channel\n");
+ dev_dbg(&drvdata->adev->dev, "send cmd id [%u]\n", ((struct CMD_CORE_GENERIC *)in_cmd)->parent.id);
+
ret = aoc_service_write_timeout(adev, in_cmd, in_size, drvdata->service_timeout);
if (ret != in_size) {
ret = -EIO;
@@ -118,6 +120,33 @@ static int aoc_usb_get_dcbaa_ptr(struct aoc_usb_drvdata *drvdata,
return 0;
}
+static int aoc_usb_set_dcbaa_ptr(struct aoc_usb_drvdata *drvdata,
+ u64 *aoc_dcbaa_ptr)
+{
+ int ret = 0;
+ struct CMD_USB_CONTROL_GET_DCBAA_PTR *cmd;
+
+ // TODO(b/192858107): Create a CMD_USB_CONTROL_SET_DCBAA_PTR instead.
+ cmd = kzalloc(sizeof(struct CMD_USB_CONTROL_GET_DCBAA_PTR), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ AocCmdHdrSet(&cmd->parent,
+ CMD_USB_CONTROL_GET_DCBAA_PTR_ID,
+ sizeof(*cmd));
+
+ cmd->aoc_dcbaa_ptr = *aoc_dcbaa_ptr;
+ ret = aoc_usb_send_command(drvdata, cmd, sizeof(*cmd), cmd, sizeof(*cmd));
+ if (ret < 0) {
+ kfree(cmd);
+ return ret;
+ }
+
+ kfree(cmd);
+
+ return 0;
+}
+
static int aoc_usb_setup_done(struct aoc_usb_drvdata *drvdata)
{
int ret;
@@ -214,6 +243,43 @@ static int aoc_usb_get_isoc_tr_info(struct aoc_usb_drvdata *drvdata, void *args)
return 0;
}
+static int aoc_usb_set_isoc_tr_info(struct aoc_usb_drvdata *drvdata, void *args)
+{
+ int ret;
+ struct get_isoc_tr_info_args *tr_info_args =
+ (struct get_isoc_tr_info_args *)args;
+ struct CMD_USB_CONTROL_GET_ISOC_TR_INFO *cmd;
+
+ // TODO(b/192858107): Create a CMD_USB_CONTROL_SET_ISOC_TR_INFO instead.
+ cmd = kzalloc(sizeof(struct CMD_USB_CONTROL_GET_ISOC_TR_INFO), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ AocCmdHdrSet(&cmd->parent,
+ CMD_USB_CONTROL_GET_ISOC_TR_INFO_ID,
+ sizeof(*cmd));
+
+ cmd->ep_id = tr_info_args->ep_id;
+ cmd->dir = tr_info_args->dir;
+ cmd->type = tr_info_args->type;
+ cmd->num_segs = tr_info_args->num_segs;
+ cmd->seg_ptr = tr_info_args->seg_ptr;
+ cmd->max_packet = tr_info_args->max_packet;
+ cmd->cycle_state = tr_info_args->cycle_state;
+ cmd->num_trbs_free = tr_info_args->num_trbs_free;
+
+ dev_dbg(&drvdata->adev->dev, "%s: ep_id=%u, dir=%u\n", __func__, cmd->ep_id, cmd->dir);
+ ret = aoc_usb_send_command(drvdata, cmd, sizeof(*cmd), cmd, sizeof(*cmd));
+ if (ret < 0) {
+ kfree(cmd);
+ return ret;
+ }
+
+ kfree(cmd);
+
+ return 0;
+}
+
static int aoc_usb_notify(struct notifier_block *this,
unsigned long code, void *data)
{
@@ -232,12 +298,18 @@ static int aoc_usb_notify(struct notifier_block *this,
case GET_DCBAA_PTR:
ret = aoc_usb_get_dcbaa_ptr(drvdata, data);
break;
+ case SET_DCBAA_PTR:
+ ret = aoc_usb_set_dcbaa_ptr(drvdata, data);
+ break;
case SETUP_DONE:
ret = aoc_usb_setup_done(drvdata);
break;
case GET_ISOC_TR_INFO:
ret = aoc_usb_get_isoc_tr_info(drvdata, data);
break;
+ case SET_ISOC_TR_INFO:
+ ret = aoc_usb_set_isoc_tr_info(drvdata, data);
+ break;
case SYNC_CONN_STAT:
ret = aoc_usb_notify_conn_stat(drvdata, data);
break;
diff --git a/usb/xhci_hooks_impl_whi.c b/usb/xhci_hooks_impl_whi.c
index 2336a0f..d74a18f 100644
--- a/usb/xhci_hooks_impl_whi.c
+++ b/usb/xhci_hooks_impl_whi.c
@@ -100,6 +100,13 @@ static int xhci_get_dcbaa_ptr(u64 *aoc_dcbaa_ptr)
return 0;
}
+static int xhci_set_dcbaa_ptr(u64 aoc_dcbaa_ptr)
+{
+ blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_DCBAA_PTR,
+ &aoc_dcbaa_ptr);
+ return 0;
+}
+
static int xhci_setup_done(void)
{
blocking_notifier_call_chain(&aoc_usb_notifier_list, SETUP_DONE, NULL);
@@ -131,6 +138,25 @@ static int xhci_get_isoc_tr_info(u16 ep_id, u16 dir, struct xhci_ring *ep_ring)
return 0;
}
+static int xhci_set_isoc_tr_info(u16 ep_id, u16 dir, struct xhci_ring *ep_ring)
+{
+ struct get_isoc_tr_info_args tr_info;
+
+ tr_info.ep_id = ep_id;
+ tr_info.dir = dir;
+ tr_info.num_segs = ep_ring->num_segs;
+ tr_info.max_packet = ep_ring->bounce_buf_len;
+ tr_info.type = ep_ring->type;
+ tr_info.seg_ptr = ep_ring->first_seg->dma;
+ tr_info.cycle_state = ep_ring->cycle_state;
+ tr_info.num_trbs_free = ep_ring->num_trbs_free;
+
+ blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_ISOC_TR_INFO,
+ &tr_info);
+
+ return 0;
+}
+
static bool is_compatible_with_usb_audio_offload(struct usb_device *udev)
{
struct usb_endpoint_descriptor *epd;
@@ -183,7 +209,7 @@ static int sync_dev_ctx(struct xhci_hcd *xhci, unsigned int slot_id)
struct xhci_vendor_data *vendor_data = xhci_to_priv(xhci)->vendor_data;
int ret = 0;
- if (vendor_data->op_mode != USB_OFFLOAD_STOP)
+ if (vendor_data->op_mode == USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY)
ret = xhci_sync_dev_ctx(xhci, slot_id);
return ret;
@@ -284,7 +310,9 @@ static int xhci_udev_notify(struct notifier_block *self, unsigned long action,
"Compatible with usb audio offload\n");
xhci_reset_for_usb_audio_offload(udev);
if (vendor_data->op_mode ==
- USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY) {
+ USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY ||
+ vendor_data->op_mode ==
+ USB_OFFLOAD_DRAM) {
xhci_sync_conn_stat(USB_CONNECTED);
}
}
@@ -292,8 +320,10 @@ static int xhci_udev_notify(struct notifier_block *self, unsigned long action,
break;
case USB_DEVICE_REMOVE:
if (is_compatible_with_usb_audio_offload(udev) &&
- vendor_data->op_mode ==
- USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY) {
+ (vendor_data->op_mode ==
+ USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY ||
+ vendor_data->op_mode ==
+ USB_OFFLOAD_DRAM)) {
xhci_sync_conn_stat(USB_DISCONNECTED);
}
vendor_data->usb_accessory_enabled = false;
@@ -389,16 +419,14 @@ static int xhci_vendor_init_irq_workqueue(struct xhci_vendor_data *vendor_data)
{
vendor_data->irq_wq = alloc_workqueue("xhci_vendor_irq_work", WQ_UNBOUND, 0);
- if (!vendor_data->irq_wq) {
+ if (!vendor_data->irq_wq)
return -ENOMEM;
- }
INIT_WORK(&vendor_data->xhci_vendor_irq_work, xhci_vendor_irq_work);
return 0;
}
-
static struct xhci_ring *
xhci_initialize_ring_info_for_remote_isoc(struct xhci_hcd *xhci,
u32 endpoint_type,
@@ -477,7 +505,7 @@ static int usb_audio_offload_init(struct xhci_hcd *xhci)
mutex_init(&vendor_data->lock);
INIT_WORK(&vendor_data->xhci_vendor_reset_ws, xhci_reset_work);
usb_register_notify(&xhci_udev_nb);
- vendor_data->op_mode = USB_OFFLOAD_STOP;
+ vendor_data->op_mode = USB_OFFLOAD_DRAM;
vendor_data->xhci = xhci;
xhci_to_priv(xhci)->vendor_data = vendor_data;
@@ -548,8 +576,13 @@ static bool is_usb_offload_enabled(struct xhci_hcd *xhci,
if (global_enabled) {
ep_ring = vdev->eps[ep_index].ring;
- if (is_dma_for_offload(ep_ring->first_seg->dma))
- return true;
+ if (vendor_data->op_mode == USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY) {
+ if (is_dma_for_offload(ep_ring->first_seg->dma))
+ return true;
+ } else if (vendor_data->op_mode == USB_OFFLOAD_DRAM) {
+ if (ep_ring->type == TYPE_ISOC)
+ return true;
+ }
}
return false;
@@ -590,6 +623,9 @@ static irqreturn_t queue_irq_work(struct xhci_hcd *xhci)
struct xhci_transfer_event *event;
u32 trb_comp_code;
+ if (vendor_data->op_mode != USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY)
+ return IRQ_NONE;
+
if (is_usb_offload_enabled(xhci, NULL, 0)) {
event = &xhci->event_ring->dequeue->trans_event;
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
@@ -623,7 +659,21 @@ static struct xhci_device_context_array *alloc_dcbaa(struct xhci_hcd *xhci,
}
xhci_setup_done();
- xhci_dbg(xhci, "write dcbaa_ptr=%llx\n", xhci->dcbaa->dma);
+ xhci_dbg(xhci, "Get dcbaa_ptr=%llx\n", xhci->dcbaa->dma);
+ } else if (vendor_data->op_mode == USB_OFFLOAD_DRAM) {
+ xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa),
+ &dma, flags);
+ if (!xhci->dcbaa)
+ return NULL;
+
+ xhci->dcbaa->dma = dma;
+ if (xhci_set_dcbaa_ptr(xhci->dcbaa->dma) != 0) {
+ xhci_err(xhci, "Set DCBAA pointer failed\n");
+ return NULL;
+ }
+ xhci_setup_done();
+
+ xhci_dbg(xhci, "Set dcbaa_ptr=%llx to AoC\n", xhci->dcbaa->dma);
} else {
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa),
&dma, flags);
@@ -658,9 +708,22 @@ static struct xhci_ring *alloc_transfer_ring(struct xhci_hcd *xhci,
u32 endpoint_type, enum xhci_ring_type ring_type,
unsigned int max_packet, gfp_t mem_flags)
{
- return xhci_initialize_ring_info_for_remote_isoc(xhci, endpoint_type,
+ struct xhci_vendor_data *vendor_data = xhci_to_priv(xhci)->vendor_data;
+ struct xhci_ring *ep_ring;
+ u16 dir;
+
+ if (vendor_data->op_mode == USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY) {
+ ep_ring = xhci_initialize_ring_info_for_remote_isoc(xhci, endpoint_type,
ring_type, max_packet,
mem_flags);
+ } else {
+ ep_ring = xhci_ring_alloc(xhci, 1, 1, ring_type, max_packet, mem_flags);
+ dir = endpoint_type == ISOC_IN_EP ? 0 : 1;
+
+ xhci_set_isoc_tr_info(0, dir, ep_ring);
+ }
+
+ return ep_ring;
}
static void free_transfer_ring(struct xhci_hcd *xhci,
@@ -677,10 +740,10 @@ static void free_transfer_ring(struct xhci_hcd *xhci,
ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
if (ring) {
- xhci_dbg(xhci, "ep_index=%u, ep_type=%u, ring type=%u\n", ep_index,
+ xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%u, ring type=%u\n", __func__, ep_index,
ep_type, ring->type);
- if (vendor_data->op_mode != USB_OFFLOAD_STOP &&
+ if (vendor_data->op_mode == USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY &&
ring->type == TYPE_ISOC) {
kfree(ring->first_seg);
kfree(virt_dev->eps[ep_index].ring);
@@ -694,10 +757,10 @@ static void free_transfer_ring(struct xhci_hcd *xhci,
}
if (new_ring) {
- xhci_dbg(xhci, "ep_index=%u, ep_type=%u, new_ring type=%u\n", ep_index,
+ xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%u, new_ring type=%u\n", __func__, ep_index,
ep_type, new_ring->type);
- if (vendor_data->op_mode != USB_OFFLOAD_STOP &&
+ if (vendor_data->op_mode == USB_OFFLOAD_SIMPLE_AUDIO_ACCESSORY &&
new_ring->type == TYPE_ISOC) {
kfree(new_ring->first_seg);
kfree(virt_dev->eps[ep_index].new_ring);
@@ -723,7 +786,7 @@ static bool usb_offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb)
ep_index = (unsigned int)(usb_endpoint_num(desc)*2) +
(usb_endpoint_dir_in(desc) ? 1 : 0) - 1;
- xhci_dbg(xhci, "ep_index=%u, ep_type=%d\n", ep_index, ep_type);
+ xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%d\n", __func__, ep_index, ep_type);
if (is_usb_offload_enabled(xhci, vdev, ep_index))
return true;