diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index a9e04938aade..0b87bebc0e6b 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -25,6 +25,8 @@ static struct gsi_inst_status { static int major; static struct class *gsi_class; static DEFINE_IDA(gsi_ida); +static DECLARE_COMPLETION(wait_for_ipa_ready); +struct ipa_usb_ops ipa_ops; /* Deregister misc device and free instance structures */ static void gsi_inst_clean(struct gsi_opts *opts); @@ -512,16 +514,12 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) GSI_EP_OP_GET_CH_INFO); log_event_dbg("%s: USB GSI IN OPS Completed", __func__); - in_params->client = - (gsi->prot_id != IPA_USB_DIAG) ? IPA_CLIENT_USB_CONS : - IPA_CLIENT_USB_DPL_CONS; - in_params->ipa_ep_cfg.mode.mode = IPA_BASIC; in_params->teth_prot = gsi->prot_id; in_params->gevntcount_low_addr = gsi_channel_info.gevntcount_low_addr; in_params->gevntcount_hi_addr = gsi_channel_info.gevntcount_hi_addr; - in_params->dir = GSI_CHAN_DIR_FROM_GSI; + in_params->dir = CHAN_DIR_FROM_GSI; in_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; in_params->xfer_scratch.last_trb_addr_iova = gsi_channel_info.last_trb_addr; @@ -569,14 +567,12 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) usb_gsi_ep_op(d_port->out_ep, (void *)&gsi_channel_info, GSI_EP_OP_GET_CH_INFO); log_event_dbg("%s: USB GSI OUT OPS Completed", __func__); - out_params->client = IPA_CLIENT_USB_PROD; - out_params->ipa_ep_cfg.mode.mode = IPA_BASIC; out_params->teth_prot = gsi->prot_id; out_params->gevntcount_low_addr = gsi_channel_info.gevntcount_low_addr; out_params->gevntcount_hi_addr = gsi_channel_info.gevntcount_hi_addr; - out_params->dir = GSI_CHAN_DIR_TO_GSI; + out_params->dir = CHAN_DIR_TO_GSI; out_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; out_params->xfer_ring_base_addr_iova = @@ -630,7 +626,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) sizeof(ipa_out_channel_out_params)); log_event_dbg("%s: Calling xdci_connect", __func__); - ret = ipa_usb_xdci_connect(out_params, in_params, + ret = d_port->ipa_ops->xdci_connect(out_params, in_params, &ipa_out_channel_out_params, &ipa_in_channel_out_params, conn_params); @@ -745,7 +741,7 @@ static void ipa_disconnect_channel(struct gsi_data_port *d_port) log_event_dbg("%s: Calling xdci_disconnect", __func__); - ret = ipa_usb_xdci_disconnect(gsi->d_port.out_channel_handle, + ret = d_port->ipa_ops->xdci_disconnect(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id); if (ret) log_event_err("%s: IPA disconnect failed %d", @@ -790,7 +786,7 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) } log_event_dbg("%s: Calling xdci_suspend", __func__); - ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, + ret = d_port->ipa_ops->xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id, usb_gsi_remote_wakeup_allowed(f)); if (!ret) { @@ -823,7 +819,7 @@ static void ipa_resume_work_handler(struct gsi_data_port *d_port) log_event_dbg("%s: Calling xdci_resume", __func__); - ret = ipa_usb_xdci_resume(gsi->d_port.out_channel_handle, + ret = d_port->ipa_ops->xdci_resume(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id); if (ret) @@ -2833,15 +2829,12 @@ fail: return -ENOMEM; } -static void ipa_ready_callback(void *user_data) +void ipa_ready_callback(void *ops) { - struct f_gsi *gsi = user_data; - - log_event_info("%s: ipa is ready\n", __func__); - - gsi->d_port.ipa_ready = true; - wake_up_interruptible(&gsi->d_port.wait_for_ipa_ready); + memcpy(&ipa_ops, ops, sizeof(struct ipa_usb_ops)); + complete_all(&wait_for_ipa_ready); } +EXPORT_SYMBOL(ipa_ready_callback); static int gsi_bind(struct usb_configuration *c, struct usb_function *f) { @@ -2909,8 +2902,8 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(gsi->params, RNDIS_MEDIUM_802_3, 0); /* export host's Ethernet address in CDC format */ - random_ether_addr(gsi->d_port.ipa_init_params.device_ethaddr); - random_ether_addr(gsi->d_port.ipa_init_params.host_ethaddr); + eth_random_addr(gsi->d_port.ipa_init_params.device_ethaddr); + eth_random_addr(gsi->d_port.ipa_init_params.host_ethaddr); log_event_dbg("setting host_ethaddr=%pM, device_ethaddr = %pM", gsi->d_port.ipa_init_params.host_ethaddr, gsi->d_port.ipa_init_params.device_ethaddr); @@ -3108,8 +3101,8 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.notify_buf_len = GSI_CTRL_NOTIFY_BUFF_LEN; /* export host's Ethernet address in CDC format */ - random_ether_addr(gsi->d_port.ipa_init_params.device_ethaddr); - random_ether_addr(gsi->d_port.ipa_init_params.host_ethaddr); + eth_random_addr(gsi->d_port.ipa_init_params.device_ethaddr); + eth_random_addr(gsi->d_port.ipa_init_params.host_ethaddr); log_event_dbg("setting host_ethaddr=%pM, device_ethaddr = %pM", gsi->d_port.ipa_init_params.host_ethaddr, gsi->d_port.ipa_init_params.device_ethaddr); @@ -3150,21 +3143,17 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto dereg_rndis; - status = ipa_register_ipa_ready_cb(ipa_ready_callback, gsi); + status = wait_for_completion_timeout(&wait_for_ipa_ready, + msecs_to_jiffies(GSI_IPA_READY_TIMEOUT)); if (!status) { - log_event_info("%s: ipa is not ready", __func__); - status = wait_event_interruptible_timeout( - gsi->d_port.wait_for_ipa_ready, gsi->d_port.ipa_ready, - msecs_to_jiffies(GSI_IPA_READY_TIMEOUT)); - if (!status) { - log_event_err("%s: ipa ready timeout", __func__); - status = -ETIMEDOUT; - goto dereg_rndis; - } + log_event_err("%s: ipa ready timeout", __func__); + status = -ETIMEDOUT; + goto dereg_rndis; } + gsi->d_port.ipa_ops = &ipa_ops; gsi->d_port.ipa_usb_notify_cb = ipa_usb_notify_cb; - status = ipa_usb_init_teth_prot(gsi->prot_id, + status = gsi->d_port.ipa_ops->init_teth_prot(gsi->prot_id, &gsi->d_port.ipa_init_params, gsi->d_port.ipa_usb_notify_cb, gsi); if (status) { @@ -3207,13 +3196,13 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) * 1. Make sure that any running work completed * 2. Make sure to wait until all pending work completed i.e. workqueue * is not having any pending work. - * Above conditions are making sure that ipa_usb_deinit_teth_prot() + * Above conditions are making sure that deinit_teth_prot() * with ipa driver shall not fail due to unexpected state. */ drain_workqueue(gsi->d_port.ipa_usb_wq); log_event_dbg("%s:id:%d: dwq end", __func__, gsi->prot_id); - ipa_usb_deinit_teth_prot(gsi->prot_id); + gsi->d_port.ipa_ops->deinit_teth_prot(gsi->prot_id); /* Reset string ids */ rndis_gsi_string_defs[0].id = 0; @@ -3310,7 +3299,7 @@ static struct f_gsi *gsi_function_init(enum ipa_usb_teth_prot prot_id) spin_lock_init(&gsi->d_port.lock); - init_waitqueue_head(&gsi->d_port.wait_for_ipa_ready); + init_completion(&wait_for_ipa_ready); INIT_DELAYED_WORK(&gsi->d_port.usb_ipa_w, ipa_work_handler); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index c14a9f8c46be..7da702ca9975 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -253,6 +252,8 @@ struct gsi_data_port { struct ipa_usb_xdci_chan_params ipa_in_channel_params; struct ipa_usb_xdci_chan_params ipa_out_channel_params; struct ipa_usb_xdci_connect_params ipa_conn_pms; + + struct ipa_usb_ops *ipa_ops; }; struct f_gsi { diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h index 2972c31a3085..be760b750fbc 100644 --- a/include/linux/ipa_usb.h +++ b/include/linux/ipa_usb.h @@ -175,181 +175,34 @@ struct ipa_req_chan_out_params { u32 db_reg_phs_addr_msb; }; -#if IS_ENABLED(CONFIG_IPA3) +struct ipa_usb_ops { + int (*init_teth_prot)(enum ipa_usb_teth_prot teth_prot, + struct ipa_usb_teth_params *teth_params, + int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *), + void *user_data); + int (*xdci_connect) + (struct ipa_usb_xdci_chan_params *ul_chan_params, + struct ipa_usb_xdci_chan_params *dl_chan_params, + struct ipa_req_chan_out_params *ul_out_params, + struct ipa_req_chan_out_params *dl_out_params, + struct ipa_usb_xdci_connect_params *connect_params); + int (*xdci_disconnect)(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot); + int (*deinit_teth_prot)(enum ipa_usb_teth_prot teth_prot); + int (*xdci_suspend)(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot, + bool with_remote_wakeup); + int (*xdci_resume)(u32 ul_clnt_hdl, u32 dl_clnt_hdl, + enum ipa_usb_teth_prot teth_prot); + bool (*ipa_usb_is_teth_prot_connected) + (enum ipa_usb_teth_prot usb_teth_prot); +}; -/** - * ipa_usb_init_teth_prot - Peripheral should call this function to initialize - * RNDIS/ECM/teth_bridge/DPL, prior to calling ipa_usb_xdci_connect() - * - * @usb_teth_type: tethering protocol type - * @teth_params: pointer to tethering protocol parameters. - * Should be struct ipa_usb_teth_params for RNDIS/ECM, - * or NULL for teth_bridge - * @ipa_usb_notify_cb: will be called to notify USB driver on certain events - * @user_data: cookie used for ipa_usb_notify_cb - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, - struct ipa_usb_teth_params *teth_params, - int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, - void *), - void *user_data); - -/** - * ipa_usb_xdci_connect - Peripheral should call this function to start IN & - * OUT xDCI channels, and connect RNDIS/ECM/MBIM/RMNET. - * For DPL, only starts IN channel. - * - * @ul_chan_params: parameters for allocating UL xDCI channel. containing - * required info on event and transfer rings, and IPA EP - * configuration - * @ul_out_params: [out] opaque client handle assigned by IPA to client & DB - * registers physical address for UL channel - * @dl_chan_params: parameters for allocating DL xDCI channel. containing - * required info on event and transfer rings, and IPA EP - * configuration - * @dl_out_params: [out] opaque client handle assigned by IPA to client & DB - * registers physical address for DL channel - * @connect_params: handles and scratch params of the required channels, - * tethering protocol and the tethering protocol parameters. - * - * Note: Should not be called from atomic context - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, - struct ipa_usb_xdci_chan_params *dl_chan_params, - struct ipa_req_chan_out_params *ul_out_params, - struct ipa_req_chan_out_params *dl_out_params, - struct ipa_usb_xdci_connect_params *connect_params); - -/** - * ipa_usb_xdci_disconnect - Peripheral should call this function to stop - * IN & OUT xDCI channels - * For DPL, only stops IN channel. - * - * @ul_clnt_hdl: client handle received from ipa_usb_xdci_connect() - * for OUT channel - * @dl_clnt_hdl: client handle received from ipa_usb_xdci_connect() - * for IN channel - * @teth_prot: tethering protocol - * - * Note: Should not be called from atomic context - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot); - -/** - * ipa_usb_deinit_teth_prot - Peripheral should call this function to deinit - * RNDIS/ECM/MBIM/RMNET - * - * @teth_prot: tethering protocol - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot); - -/** - * ipa_usb_xdci_suspend - Peripheral should call this function to suspend - * IN & OUT or DPL xDCI channels - * - * @ul_clnt_hdl: client handle previously obtained from - * ipa_usb_xdci_connect() for OUT channel - * @dl_clnt_hdl: client handle previously obtained from - * ipa_usb_xdci_connect() for IN channel - * @teth_prot: tethering protocol - * @with_remote_wakeup: Does host support remote wakeup? - * - * Note: Should not be called from atomic context - * Note: for DPL, the ul will be ignored as irrelevant - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot, - bool with_remote_wakeup); - -/** - * ipa_usb_xdci_resume - Peripheral should call this function to resume - * IN & OUT or DPL xDCI channels - * - * @ul_clnt_hdl: client handle received from ipa_usb_xdci_connect() - * for OUT channel - * @dl_clnt_hdl: client handle received from ipa_usb_xdci_connect() - * for IN channel - * @teth_prot: tethering protocol - * - * Note: Should not be called from atomic context - * Note: for DPL, the ul will be ignored as irrelevant - * - * @Return 0 on success, negative on failure - */ -int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot); - -/** - * ipa_usb_is_teth_prot_connected - Internal API for checking USB - * protocol is connected - * - * @usb_teth_prot: USB tethering protocol - * @Return true if connected, false if not - */ -bool ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot); - -#else /* IS_ENABLED(CONFIG_IPA3) */ - -static inline int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, - struct ipa_usb_teth_params *teth_params, - int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, - void *), - void *user_data) -{ - return -EPERM; -} - -static inline int ipa_usb_xdci_connect( - struct ipa_usb_xdci_chan_params *ul_chan_params, - struct ipa_usb_xdci_chan_params *dl_chan_params, - struct ipa_req_chan_out_params *ul_out_params, - struct ipa_req_chan_out_params *dl_out_params, - struct ipa_usb_xdci_connect_params *connect_params) -{ - return -EPERM; -} - -static inline int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot) -{ - return -EPERM; -} - -static inline int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) -{ - return -EPERM; -} - -static inline int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot, - bool with_remote_wakeup) -{ - return -EPERM; -} - -static inline int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, - enum ipa_usb_teth_prot teth_prot) -{ - return -EPERM; -} - -static inline int ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot) -{ - return -EPERM; -} - - -#endif /* IS_ENABLED(CONFIG_IPA3) */ +#if IS_ENABLED(CONFIG_USB_F_GSI) +void ipa_ready_callback(void *ops); +#else +static inline void ipa_ready_callback(void *ops) +{ } +#endif #endif /* _IPA_USB_H_ */ diff --git a/include/uapi/linux/usb/usb_ctrl_qti.h b/include/uapi/linux/usb/usb_ctrl_qti.h new file mode 100644 index 000000000000..11b04c8062f7 --- /dev/null +++ b/include/uapi/linux/usb/usb_ctrl_qti.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef __UAPI_LINUX_USB_CTRL_QTI_H +#define __UAPI_LINUX_USB_CTRL_QTI_H + +#include +#include + +#define MAX_QTI_PKT_SIZE 2048 + +#define QTI_CTRL_IOCTL_MAGIC 'r' +#define QTI_CTRL_GET_LINE_STATE _IOR(QTI_CTRL_IOCTL_MAGIC, 2, int) +#define QTI_CTRL_EP_LOOKUP _IOR(QTI_CTRL_IOCTL_MAGIC, 3, struct ep_info) +#define QTI_CTRL_MODEM_OFFLINE _IO(QTI_CTRL_IOCTL_MAGIC, 4) +#define QTI_CTRL_MODEM_ONLINE _IO(QTI_CTRL_IOCTL_MAGIC, 5) +#define QTI_CTRL_DATA_BUF_INFO \ + _IOR(QTI_CTRL_IOCTL_MAGIC, 6, struct data_buf_info) + +#define GSI_MBIM_IOCTL_MAGIC 'o' +#define GSI_MBIM_GET_NTB_SIZE _IOR(GSI_MBIM_IOCTL_MAGIC, 2, __u32) +#define GSI_MBIM_GET_DATAGRAM_COUNT _IOR(GSI_MBIM_IOCTL_MAGIC, 3, __u16) +#define GSI_MBIM_EP_LOOKUP _IOR(GSI_MBIM_IOCTL_MAGIC, 4, struct ep_info) +#define GSI_MBIM_GPS_USB_STATUS _IOR(GSI_MBIM_IOCTL_MAGIC, 5, int) + +enum peripheral_ep_type { + DATA_EP_TYPE_RESERVED = 0x0, + DATA_EP_TYPE_HSIC = 0x1, + DATA_EP_TYPE_HSUSB = 0x2, + DATA_EP_TYPE_PCIE = 0x3, + DATA_EP_TYPE_EMBEDDED = 0x4, + DATA_EP_TYPE_BAM_DMUX = 0x5, +}; + +struct peripheral_ep_info { + enum peripheral_ep_type ep_type; + __u32 peripheral_iface_id; +}; + +struct ipa_ep_pair { + __u32 cons_pipe_num; + __u32 prod_pipe_num; +}; + +struct ep_info { + struct peripheral_ep_info ph_ep_info; + struct ipa_ep_pair ipa_ep_pair; + +}; + +struct data_buf_info { + __u32 epout_buf_len; + __u32 epout_total_buf_len; + __u32 epin_buf_len; + __u32 epin_total_buf_len; +}; + +#endif