msm: ipa: initial commit of IPA driver

This is a snapshot of IPA from kernel msm-4.4 based on
commit ebc2a18351d4 ("msm: ipa: WA to get PA of sgt_tbl from wlan")

CRs-Fixed: 1077422
Change-Id: I97cf9ee9c104ac5ab5bc0577eb9413264b08a7a5
Signed-off-by: Amir Levy <alevy@codeaurora.org>
This commit is contained in:
Amir Levy 2016-10-27 18:08:27 +03:00
commit 9659e593c8
110 changed files with 114401 additions and 0 deletions

View file

@ -0,0 +1,207 @@
Qualcomm technologies inc. Internet Packet Accelerator
Internet Packet Accelerator (IPA) is a programmable protocol
processor HW block. It is designed to support generic HW processing
of UL/DL IP packets for various use cases independent of radio technology.
Required properties:
IPA node:
- compatible : "qcom,ipa"
- reg: Specifies the base physical addresses and the sizes of the IPA
registers.
- reg-names: "ipa-base" - string to identify the IPA CORE base registers.
"bam-base" - string to identify the IPA BAM base registers.
"a2-bam-base" - string to identify the A2 BAM base registers.
- interrupts: Specifies the interrupt associated with IPA.
- interrupt-names: "ipa-irq" - string to identify the IPA core interrupt.
"bam-irq" - string to identify the IPA BAM interrupt.
"a2-bam-irq" - string to identify the A2 BAM interrupt.
- qcom,ipa-hw-ver: Specifies the IPA hardware version.
Optional:
- qcom,wan-rx-ring-size: size of WAN rx ring, default is 32
- qcom,arm-smmu: SMMU is present and ARM SMMU driver is used
- qcom,msm-smmu: SMMU is present and QSMMU driver is used
- qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
- qcom,smmu-fast-map: Boolean context flag to set SMMU to fastpath mode
- ipa_smmu_ap: AP general purpose SMMU device
compatible "qcom,ipa-smmu-ap-cb"
- ipa_smmu_wlan: WDI SMMU device
compatible "qcom,ipa-smmu-wlan-cb"
- ipa_smmu_uc: uc SMMU device
compatible "qcom,ipa-smmu-uc-cb"
- qcom,smmu-disable-htw: boolean value to turn off SMMU page table caching
- qcom,use-a2-service: determine if A2 service will be used
- qcom,use-ipa-tethering-bridge: determine if tethering bridge will be used
- qcom,use-ipa-bamdma-a2-bridge: determine if a2/ipa hw bridge will be used
- qcom,ee: which EE is assigned to (non-secure) APPS from IPA-BAM POV. This
is a number
- qcom,ipa-hw-mode: IPA hardware mode - Normal, Virtual memory allocation,
memory allocation over a PCIe bridge
- qcom,msm-bus,name: String representing the client-name
- qcom,msm-bus,num-cases: Total number of usecases
- qcom,msm-bus,active-only: Boolean context flag for requests in active or
dual (active & sleep) contex
- qcom,msm-bus,num-paths: Total number of master-slave pairs
- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing:
master-id, slave-id, arbitrated bandwidth
in KBps, instantaneous bandwidth in KBps
- qcom,ipa-bam-remote-mode: Boolean context flag to determine if ipa bam
is in remote mode.
- qcom,modem-cfg-emb-pipe-flt: Boolean context flag to determine if modem
configures embedded pipe filtering rules
- qcom,skip-uc-pipe-reset: Boolean context flag to indicate whether
a pipe reset via the IPA uC is required
- qcom,ipa-wdi2: Boolean context flag to indicate whether
using wdi-2.0 or not
- qcom,use-dma-zone: Boolean context flag to indicate whether memory
allocations controlled by IPA driver that do not
specify a struct device * should use GFP_DMA to
workaround IPA HW limitations
- qcom,use-gsi: Boolean context flag to indicate if the
transport protocol is GSI
- qcom,use-rg10-limitation-mitigation: Boolean context flag to activate
the mitigation to register group 10
AP access limitation
- qcom,do-not-use-ch-gsi-20: Boolean context flag to activate
software workaround for IPA limitation
to not use GSI physical channel 20
- qcom,tethered-flow-control: Boolean context flag to indicate whether
apps based flow control is needed for tethered
call.
IPA pipe sub nodes (A2 static pipes configurations):
-label: two labels are supported, a2-to-ipa and ipa-to-a2 which
supply static configuration for A2-IPA connection.
-qcom,src-bam-physical-address: The physical address of the source BAM
-qcom,ipa-bam-mem-type:The memory type:
0(Pipe memory), 1(Private memory), 2(System memory)
-qcom,src-bam-pipe-index: Source pipe index
-qcom,dst-bam-physical-address: The physical address of the
destination BAM
-qcom,dst-bam-pipe-index: Destination pipe index
-qcom,data-fifo-offset: Data fifo base offset
-qcom,data-fifo-size: Data fifo size (bytes)
-qcom,descriptor-fifo-offset: Descriptor fifo base offset
-qcom,descriptor-fifo-size: Descriptor fifo size (bytes)
Optional properties:
-qcom,ipa-pipe-mem: Specifies the base physical address and the
size of the IPA pipe memory region.
Pipe memory is a feature which may be supported by the
target (HW platform). The Driver support using pipe
memory instead of system memory. In case this property
will not appear in the IPA DTS entry, the driver will
use system memory.
- clocks: This property shall provide a list of entries each of which
contains a phandle to clock controller device and a macro that is
the clock's name in hardware.This should be "clock_rpm" as clock
controller phandle and "clk_ipa_clk" as macro for "iface_clk"
- clock-names: This property shall contain the clock input names used
by driver in same order as the clocks property.This should be "iface_clk"
IPA SMMU sub nodes
-compatible: "qcom,ipa-smmu-ap-cb" - represents the AP context bank.
-compatible: "qcom,ipa-smmu-wlan-cb" - represents IPA WLAN context bank.
-compatible: "qcom,ipa-smmu-uc-cb" - represents IPA uC context bank (for uC
offload scenarios).
- iommus : the phandle and stream IDs for the SMMU used by this root
- qcom,iova-mapping: specifies the start address and size of iova space.
IPA SMP2P sub nodes
-compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
ipa driver to modem.
-compatible: "qcom,smp2pgpio-map-ipa-1-in" - represents the in gpio to
ipa driver from modem.
-gpios: Binding to the gpio defined in XXX-smp2p.dtsi
Example:
qcom,ipa@fd4c0000 {
compatible = "qcom,ipa";
reg = <0xfd4c0000 0x26000>,
<0xfd4c4000 0x14818>;
<0xfc834000 0x7000>;
reg-names = "ipa-base", "bam-base"; "a2-bam-base";
interrupts = <0 252 0>,
<0 253 0>;
<0 29 1>;
interrupt-names = "ipa-irq", "bam-irq"; "a2-bam-irq";
qcom,ipa-hw-ver = <1>;
clocks = <&clock_rpm clk_ipa_clk>;
clock-names = "iface_clk";
qcom,msm-bus,name = "ipa";
qcom,msm-bus,num-cases = <3>;
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<90 512 0 0>, <90 585 0 0>, /* No vote */
<90 512 100000 800000>, <90 585 100000 800000>, /* SVS */
<90 512 100000 1200000>, <90 585 100000 1200000>; /* PERF */
qcom,bus-vector-names = "MIN", "SVS", "PERF";
qcom,pipe1 {
label = "a2-to-ipa";
qcom,src-bam-physical-address = <0xfc834000>;
qcom,ipa-bam-mem-type = <0>;
qcom,src-bam-pipe-index = <1>;
qcom,dst-bam-physical-address = <0xfd4c0000>;
qcom,dst-bam-pipe-index = <6>;
qcom,data-fifo-offset = <0x1000>;
qcom,data-fifo-size = <0xd00>;
qcom,descriptor-fifo-offset = <0x1d00>;
qcom,descriptor-fifo-size = <0x300>;
};
qcom,pipe2 {
label = "ipa-to-a2";
qcom,src-bam-physical-address = <0xfd4c0000>;
qcom,ipa-bam-mem-type = <0>;
qcom,src-bam-pipe-index = <7>;
qcom,dst-bam-physical-address = <0xfc834000>;
qcom,dst-bam-pipe-index = <0>;
qcom,data-fifo-offset = <0x00>;
qcom,data-fifo-size = <0xd00>;
qcom,descriptor-fifo-offset = <0xd00>;
qcom,descriptor-fifo-size = <0x300>;
};
/* smp2p gpio information */
qcom,smp2pgpio_map_ipa_1_out {
compatible = "qcom,smp2pgpio-map-ipa-1-out";
gpios = <&smp2pgpio_ipa_1_out 0 0>;
};
qcom,smp2pgpio_map_ipa_1_in {
compatible = "qcom,smp2pgpio-map-ipa-1-in";
gpios = <&smp2pgpio_ipa_1_in 0 0>;
};
ipa_smmu_ap: ipa_smmu_ap {
compatible = "qcom,ipa-smmu-ap-cb";
iommus = <&anoc2_smmu 0x30>;
qcom,iova-mapping = <0x10000000 0x40000000>;
};
ipa_smmu_wlan: ipa_smmu_wlan {
compatible = "qcom,ipa-smmu-wlan-cb";
iommus = <&anoc2_smmu 0x31>;
};
ipa_smmu_uc: ipa_smmu_uc {
compatible = "qcom,ipa-smmu-uc-cb";
iommus = <&anoc2_smmu 0x32>;
qcom,iova-mapping = <0x40000000 0x20000000>;
};
};

View file

@ -0,0 +1,18 @@
* Qualcomm Technologies, Inc. RmNet IPA driver module
This module enables embedded data calls using IPA HW.
Required properties:
- compatible: Must be "qcom,rmnet-ipa"
Optional:
- qcom,rmnet-ipa-ssr: determine if modem SSR is supported
- qcom,ipa-loaduC: indicate that ipa uC should be loaded
- qcom,ipa-advertise-sg-support: determine how to respond to a query
regarding scatter-gather capability
Example:
qcom,rmnet-ipa {
compatible = "qcom,rmnet-ipa";
}

View file

@ -0,0 +1,18 @@
* Qualcomm Technologies, Inc. RmNet IPA driver module
This module enables embedded data calls using IPA v3 HW.
Required properties:
- compatible: Must be "qcom,rmnet-ipa3"
Optional:
- qcom,rmnet-ipa-ssr: determine if modem SSR is supported
- qcom,ipa-loaduC: indicate that ipa uC should be loaded
- qcom,ipa-advertise-sg-support: determine how to respond to a query
regarding scatter-gather capability
Example:
qcom,rmnet-ipa3 {
compatible = "qcom,rmnet-ipa3";
}

View file

@ -8,3 +8,5 @@ endif
source "drivers/platform/goldfish/Kconfig"
source "drivers/platform/chrome/Kconfig"
source "drivers/platform/msm/Kconfig"

View file

@ -7,3 +7,4 @@ obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
obj-$(CONFIG_ARCH_QCOM) += msm/

View file

@ -0,0 +1,68 @@
menu "Qualcomm technologies inc. MSM specific device drivers"
depends on ARCH_QCOM
config IPA
tristate "IPA support"
depends on SPS && NET
help
This driver supports the Internet Packet Accelerator (IPA) core.
IPA is a programmable protocol processor HW block.
It is designed to support generic HW processing of UL/DL IP packets
for various use cases independent of radio technology.
The driver support client connection and configuration
for the IPA core.
Kernel and user-space processes can call the IPA driver
to configure IPA core.
config RMNET_IPA
tristate "IPA RMNET WWAN Network Device"
depends on IPA && MSM_QMI_INTERFACE
help
This WWAN Network Driver implements network stack class device.
It supports Embedded data transfer from A7 to Q6. Configures IPA HW
for RmNet Data Driver and also exchange of QMI messages between
A7 and Q6 IPA-driver.
config GSI
bool "GSI support"
help
This driver provides the transport needed to talk to the
IPA core. It replaces the BAM transport used previously.
The GSI connects to a peripheral component via uniform TLV
interface, and allows it to interface with other peripherals
and CPUs over various types of interfaces such as MHI, xDCI,
xHCI, GPI, WDI, Ethernet, etc.
config IPA3
tristate "IPA3 support"
depends on GSI && NET
help
This driver supports the Internet Packet Accelerator (IPA3) core.
IPA is a programmable protocol processor HW block.
It is designed to support generic HW processing of UL/DL IP packets
for various use cases independent of radio technology.
The driver support client connection and configuration
for the IPA core.
Kernel and user-space processes can call the IPA driver
to configure IPA core.
config RMNET_IPA3
tristate "IPA3 RMNET WWAN Network Device"
depends on IPA3 && MSM_QMI_INTERFACE
help
This WWAN Network Driver implements network stack class device.
It supports Embedded data transfer from A7 to Q6. Configures IPA HW
for RmNet Data Driver and also exchange of QMI messages between
A7 and Q6 IPA-driver.
config IPA_UT
tristate "IPA Unit-Test Framework and Test Suites"
depends on IPA3 && DEBUG_FS
help
This Module implements IPA in-kernel test framework.
The framework supports defining and running tests, grouped
into suites according to the sub-unit of the IPA being tested.
The user interface to run and control the tests is debugfs file
system.
endmenu

View file

@ -0,0 +1,6 @@
#
# Makefile for the MSM specific device drivers.
#
obj-$(CONFIG_GSI) += gsi/
obj-$(CONFIG_IPA) += ipa/
obj-$(CONFIG_IPA3) += ipa/

View file

@ -0,0 +1,5 @@
obj-$(CONFIG_IPA) += ipa_v2/ ipa_clients/ ipa_common
obj-$(CONFIG_IPA3) += ipa_v3/ ipa_clients/ ipa_common
obj-$(CONFIG_IPA_UT) += test/
ipa_common += ipa_api.o ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,400 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/ipa_mhi.h>
#include <linux/ipa_uc_offload.h>
#include "ipa_common_i.h"
#ifndef _IPA_API_H_
#define _IPA_API_H_
struct ipa_api_controller {
int (*ipa_connect)(const struct ipa_connect_params *in,
struct ipa_sps_params *sps, u32 *clnt_hdl);
int (*ipa_disconnect)(u32 clnt_hdl);
int (*ipa_reset_endpoint)(u32 clnt_hdl);
int (*ipa_clear_endpoint_delay)(u32 clnt_hdl);
int (*ipa_disable_endpoint)(u32 clnt_hdl);
int (*ipa_cfg_ep)(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);
int (*ipa_cfg_ep_nat)(u32 clnt_hdl,
const struct ipa_ep_cfg_nat *ipa_ep_cfg);
int (*ipa_cfg_ep_hdr)(u32 clnt_hdl,
const struct ipa_ep_cfg_hdr *ipa_ep_cfg);
int (*ipa_cfg_ep_hdr_ext)(u32 clnt_hdl,
const struct ipa_ep_cfg_hdr_ext *ipa_ep_cfg);
int (*ipa_cfg_ep_mode)(u32 clnt_hdl,
const struct ipa_ep_cfg_mode *ipa_ep_cfg);
int (*ipa_cfg_ep_aggr)(u32 clnt_hdl,
const struct ipa_ep_cfg_aggr *ipa_ep_cfg);
int (*ipa_cfg_ep_deaggr)(u32 clnt_hdl,
const struct ipa_ep_cfg_deaggr *ipa_ep_cfg);
int (*ipa_cfg_ep_route)(u32 clnt_hdl,
const struct ipa_ep_cfg_route *ipa_ep_cfg);
int (*ipa_cfg_ep_holb)(u32 clnt_hdl,
const struct ipa_ep_cfg_holb *ipa_ep_cfg);
int (*ipa_cfg_ep_cfg)(u32 clnt_hdl,
const struct ipa_ep_cfg_cfg *ipa_ep_cfg);
int (*ipa_cfg_ep_metadata_mask)(u32 clnt_hdl,
const struct ipa_ep_cfg_metadata_mask *ipa_ep_cfg);
int (*ipa_cfg_ep_holb_by_client)(enum ipa_client_type client,
const struct ipa_ep_cfg_holb *ipa_ep_cfg);
int (*ipa_cfg_ep_ctrl)(u32 clnt_hdl,
const struct ipa_ep_cfg_ctrl *ep_ctrl);
int (*ipa_add_hdr)(struct ipa_ioc_add_hdr *hdrs);
int (*ipa_del_hdr)(struct ipa_ioc_del_hdr *hdls);
int (*ipa_commit_hdr)(void);
int (*ipa_reset_hdr)(void);
int (*ipa_get_hdr)(struct ipa_ioc_get_hdr *lookup);
int (*ipa_put_hdr)(u32 hdr_hdl);
int (*ipa_copy_hdr)(struct ipa_ioc_copy_hdr *copy);
int (*ipa_add_hdr_proc_ctx)(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);
int (*ipa_del_hdr_proc_ctx)(struct ipa_ioc_del_hdr_proc_ctx *hdls);
int (*ipa_add_rt_rule)(struct ipa_ioc_add_rt_rule *rules);
int (*ipa_del_rt_rule)(struct ipa_ioc_del_rt_rule *hdls);
int (*ipa_commit_rt)(enum ipa_ip_type ip);
int (*ipa_reset_rt)(enum ipa_ip_type ip);
int (*ipa_get_rt_tbl)(struct ipa_ioc_get_rt_tbl *lookup);
int (*ipa_put_rt_tbl)(u32 rt_tbl_hdl);
int (*ipa_query_rt_index)(struct ipa_ioc_get_rt_tbl_indx *in);
int (*ipa_mdfy_rt_rule)(struct ipa_ioc_mdfy_rt_rule *rules);
int (*ipa_add_flt_rule)(struct ipa_ioc_add_flt_rule *rules);
int (*ipa_del_flt_rule)(struct ipa_ioc_del_flt_rule *hdls);
int (*ipa_mdfy_flt_rule)(struct ipa_ioc_mdfy_flt_rule *rules);
int (*ipa_commit_flt)(enum ipa_ip_type ip);
int (*ipa_reset_flt)(enum ipa_ip_type ip);
int (*allocate_nat_device)(struct ipa_ioc_nat_alloc_mem *mem);
int (*ipa_nat_init_cmd)(struct ipa_ioc_v4_nat_init *init);
int (*ipa_nat_dma_cmd)(struct ipa_ioc_nat_dma_cmd *dma);
int (*ipa_nat_del_cmd)(struct ipa_ioc_v4_nat_del *del);
int (*ipa_send_msg)(struct ipa_msg_meta *meta, void *buff,
ipa_msg_free_fn callback);
int (*ipa_register_pull_msg)(struct ipa_msg_meta *meta,
ipa_msg_pull_fn callback);
int (*ipa_deregister_pull_msg)(struct ipa_msg_meta *meta);
int (*ipa_register_intf)(const char *name,
const struct ipa_tx_intf *tx,
const struct ipa_rx_intf *rx);
int (*ipa_register_intf_ext)(const char *name,
const struct ipa_tx_intf *tx,
const struct ipa_rx_intf *rx,
const struct ipa_ext_intf *ext);
int (*ipa_deregister_intf)(const char *name);
int (*ipa_set_aggr_mode)(enum ipa_aggr_mode mode);
int (*ipa_set_qcncm_ndp_sig)(char sig[3]);
int (*ipa_set_single_ndp_per_mbim)(bool enable);
int (*ipa_tx_dp)(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa_tx_meta *metadata);
int (*ipa_tx_dp_mul)(enum ipa_client_type dst,
struct ipa_tx_data_desc *data_desc);
void (*ipa_free_skb)(struct ipa_rx_data *);
int (*ipa_setup_sys_pipe)(struct ipa_sys_connect_params *sys_in,
u32 *clnt_hdl);
int (*ipa_teardown_sys_pipe)(u32 clnt_hdl);
int (*ipa_sys_setup)(struct ipa_sys_connect_params *sys_in,
unsigned long *ipa_bam_hdl,
u32 *ipa_pipe_num, u32 *clnt_hdl, bool en_status);
int (*ipa_sys_teardown)(u32 clnt_hdl);
int (*ipa_sys_update_gsi_hdls)(u32 clnt_hdl, unsigned long gsi_ch_hdl,
unsigned long gsi_ev_hdl);
int (*ipa_connect_wdi_pipe)(struct ipa_wdi_in_params *in,
struct ipa_wdi_out_params *out);
int (*ipa_disconnect_wdi_pipe)(u32 clnt_hdl);
int (*ipa_enable_wdi_pipe)(u32 clnt_hdl);
int (*ipa_disable_wdi_pipe)(u32 clnt_hdl);
int (*ipa_resume_wdi_pipe)(u32 clnt_hdl);
int (*ipa_suspend_wdi_pipe)(u32 clnt_hdl);
int (*ipa_get_wdi_stats)(struct IpaHwStatsWDIInfoData_t *stats);
u16 (*ipa_get_smem_restr_bytes)(void);
int (*ipa_uc_wdi_get_dbpa)(struct ipa_wdi_db_params *out);
int (*ipa_uc_reg_rdyCB)(struct ipa_wdi_uc_ready_params *param);
int (*ipa_uc_dereg_rdyCB)(void);
int (*teth_bridge_init)(struct teth_bridge_init_params *params);
int (*teth_bridge_disconnect)(enum ipa_client_type client);
int (*teth_bridge_connect)(
struct teth_bridge_connect_params *connect_params);
void (*ipa_set_client)(
int index, enum ipacm_client_enum client, bool uplink);
enum ipacm_client_enum (*ipa_get_client)(int pipe_idx);
bool (*ipa_get_client_uplink)(int pipe_idx);
int (*ipa_dma_init)(void);
int (*ipa_dma_enable)(void);
int (*ipa_dma_disable)(void);
int (*ipa_dma_sync_memcpy)(u64 dest, u64 src, int len);
int (*ipa_dma_async_memcpy)(u64 dest, u64 src, int len,
void (*user_cb)(void *user1), void *user_param);
int (*ipa_dma_uc_memcpy)(phys_addr_t dest, phys_addr_t src, int len);
void (*ipa_dma_destroy)(void);
bool (*ipa_has_open_aggr_frame)(enum ipa_client_type client);
int (*ipa_generate_tag_process)(void);
int (*ipa_disable_sps_pipe)(enum ipa_client_type client);
void (*ipa_set_tag_process_before_gating)(bool val);
int (*ipa_mhi_init_engine)(struct ipa_mhi_init_engine *params);
int (*ipa_connect_mhi_pipe)(struct ipa_mhi_connect_params_internal *in,
u32 *clnt_hdl);
int (*ipa_disconnect_mhi_pipe)(u32 clnt_hdl);
bool (*ipa_mhi_stop_gsi_channel)(enum ipa_client_type client);
int (*ipa_qmi_disable_force_clear)(u32 request_id);
int (*ipa_qmi_enable_force_clear_datapath_send)(
struct ipa_enable_force_clear_datapath_req_msg_v01 *req);
int (*ipa_qmi_disable_force_clear_datapath_send)(
struct ipa_disable_force_clear_datapath_req_msg_v01 *req);
bool (*ipa_mhi_sps_channel_empty)(enum ipa_client_type client);
int (*ipa_mhi_reset_channel_internal)(enum ipa_client_type client);
int (*ipa_mhi_start_channel_internal)(enum ipa_client_type client);
void (*ipa_get_holb)(int ep_idx, struct ipa_ep_cfg_holb *holb);
int (*ipa_mhi_query_ch_info)(enum ipa_client_type client,
struct gsi_chan_info *ch_info);
int (*ipa_mhi_resume_channels_internal)(
enum ipa_client_type client,
bool LPTransitionRejected,
bool brstmode_enabled,
union __packed gsi_channel_scratch ch_scratch,
u8 index);
int (*ipa_mhi_destroy_channel)(enum ipa_client_type client);
int (*ipa_uc_mhi_send_dl_ul_sync_info)
(union IpaHwMhiDlUlSyncCmdData_t *cmd);
int (*ipa_uc_mhi_init)
(void (*ready_cb)(void), void (*wakeup_request_cb)(void));
void (*ipa_uc_mhi_cleanup)(void);
int (*ipa_uc_mhi_print_stats)(char *dbg_buff, int size);
int (*ipa_uc_mhi_reset_channel)(int channelHandle);
int (*ipa_uc_mhi_suspend_channel)(int channelHandle);
int (*ipa_uc_mhi_stop_event_update_channel)(int channelHandle);
int (*ipa_uc_state_check)(void);
int (*ipa_write_qmap_id)(struct ipa_ioc_write_qmapid *param_in);
int (*ipa_add_interrupt_handler)(enum ipa_irq_type interrupt,
ipa_irq_handler_t handler,
bool deferred_flag,
void *private_data);
int (*ipa_remove_interrupt_handler)(enum ipa_irq_type interrupt);
int (*ipa_restore_suspend_handler)(void);
void (*ipa_bam_reg_dump)(void);
int (*ipa_get_ep_mapping)(enum ipa_client_type client);
bool (*ipa_is_ready)(void);
void (*ipa_proxy_clk_vote)(void);
void (*ipa_proxy_clk_unvote)(void);
bool (*ipa_is_client_handle_valid)(u32 clnt_hdl);
enum ipa_client_type (*ipa_get_client_mapping)(int pipe_idx);
enum ipa_rm_resource_name (*ipa_get_rm_resource_from_ep)(int pipe_idx);
bool (*ipa_get_modem_cfg_emb_pipe_flt)(void);
enum ipa_transport_type (*ipa_get_transport_type)(void);
int (*ipa_ap_suspend)(struct device *dev);
int (*ipa_ap_resume)(struct device *dev);
int (*ipa_stop_gsi_channel)(u32 clnt_hdl);
struct iommu_domain *(*ipa_get_smmu_domain)(void);
int (*ipa_disable_apps_wan_cons_deaggr)(uint32_t agg_size,
uint32_t agg_count);
struct device *(*ipa_get_dma_dev)(void);
int (*ipa_release_wdi_mapping)(u32 num_buffers,
struct ipa_wdi_buffer_info *info);
int (*ipa_create_wdi_mapping)(u32 num_buffers,
struct ipa_wdi_buffer_info *info);
struct ipa_gsi_ep_config *(*ipa_get_gsi_ep_info)(int ipa_ep_idx);
int (*ipa_register_ipa_ready_cb)(void (*ipa_ready_cb)(void *user_data),
void *user_data);
void (*ipa_inc_client_enable_clks)(
struct ipa_active_client_logging_info *id);
void (*ipa_dec_client_disable_clks)(
struct ipa_active_client_logging_info *id);
int (*ipa_inc_client_enable_clks_no_block)(
struct ipa_active_client_logging_info *id);
int (*ipa_suspend_resource_no_block)(
enum ipa_rm_resource_name resource);
int (*ipa_resume_resource)(enum ipa_rm_resource_name name);
int (*ipa_suspend_resource_sync)(enum ipa_rm_resource_name resource);
int (*ipa_set_required_perf_profile)(
enum ipa_voltage_level floor_voltage, u32 bandwidth_mbps);
void *(*ipa_get_ipc_logbuf)(void);
void *(*ipa_get_ipc_logbuf_low)(void);
int (*ipa_rx_poll)(u32 clnt_hdl, int budget);
void (*ipa_recycle_wan_skb)(struct sk_buff *skb);
int (*ipa_setup_uc_ntn_pipes)(struct ipa_ntn_conn_in_params *in,
ipa_notify_cb notify, void *priv, u8 hdr_len,
struct ipa_ntn_conn_out_params *);
int (*ipa_tear_down_uc_offload_pipes)(int ipa_ep_idx_ul,
int ipa_ep_idx_dl);
};
#ifdef CONFIG_IPA
int ipa_plat_drv_probe(struct platform_device *pdev_p,
struct ipa_api_controller *api_ctrl,
const struct of_device_id *pdrv_match);
#else
static inline int ipa_plat_drv_probe(struct platform_device *pdev_p,
struct ipa_api_controller *api_ctrl,
const struct of_device_id *pdrv_match)
{
return -ENODEV;
}
#endif /* (CONFIG_IPA) */
#ifdef CONFIG_IPA3
int ipa3_plat_drv_probe(struct platform_device *pdev_p,
struct ipa_api_controller *api_ctrl,
const struct of_device_id *pdrv_match);
#else
static inline int ipa3_plat_drv_probe(struct platform_device *pdev_p,
struct ipa_api_controller *api_ctrl,
const struct of_device_id *pdrv_match)
{
return -ENODEV;
}
#endif /* (CONFIG_IPA3) */
#endif /* _IPA_API_H_ */

View file

@ -0,0 +1,2 @@
obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o
obj-$(CONFIG_IPA) += odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,597 @@
/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/ipa_uc_offload.h>
#include <linux/msm_ipa.h>
#include "../ipa_common_i.h"
#define IPA_NTN_DMA_POOL_ALIGNMENT 8
#define OFFLOAD_DRV_NAME "ipa_uc_offload"
#define IPA_UC_OFFLOAD_DBG(fmt, args...) \
do { \
pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UC_OFFLOAD_LOW(fmt, args...) \
do { \
pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UC_OFFLOAD_ERR(fmt, args...) \
do { \
pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UC_OFFLOAD_INFO(fmt, args...) \
do { \
pr_info(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
enum ipa_uc_offload_state {
IPA_UC_OFFLOAD_STATE_INVALID,
IPA_UC_OFFLOAD_STATE_INITIALIZED,
IPA_UC_OFFLOAD_STATE_UP,
IPA_UC_OFFLOAD_STATE_DOWN,
};
struct ipa_uc_offload_ctx {
enum ipa_uc_offload_proto proto;
enum ipa_uc_offload_state state;
void *priv;
u8 hdr_len;
u32 partial_hdr_hdl[IPA_IP_MAX];
char netdev_name[IPA_RESOURCE_NAME_MAX];
ipa_notify_cb notify;
struct completion ntn_completion;
};
static struct ipa_uc_offload_ctx *ipa_uc_offload_ctx[IPA_UC_MAX_PROT_SIZE];
static int ipa_commit_partial_hdr(
struct ipa_ioc_add_hdr *hdr,
const char *netdev_name,
struct ipa_hdr_info *hdr_info)
{
int i;
if (hdr == NULL || hdr_info == NULL) {
IPA_UC_OFFLOAD_ERR("Invalid input\n");
return -EINVAL;
}
hdr->commit = 1;
hdr->num_hdrs = 2;
snprintf(hdr->hdr[0].name, sizeof(hdr->hdr[0].name),
"%s_ipv4", netdev_name);
snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name),
"%s_ipv6", netdev_name);
for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) {
hdr->hdr[i].hdr_len = hdr_info[i].hdr_len;
memcpy(hdr->hdr[i].hdr, hdr_info[i].hdr, hdr->hdr[i].hdr_len);
hdr->hdr[i].type = hdr_info[i].hdr_type;
hdr->hdr[i].is_partial = 1;
hdr->hdr[i].is_eth2_ofst_valid = 1;
hdr->hdr[i].eth2_ofst = hdr_info[i].dst_mac_addr_offset;
}
if (ipa_add_hdr(hdr)) {
IPA_UC_OFFLOAD_ERR("fail to add partial headers\n");
return -EFAULT;
}
return 0;
}
static int ipa_uc_offload_ntn_reg_intf(
struct ipa_uc_offload_intf_params *inp,
struct ipa_uc_offload_out_params *outp,
struct ipa_uc_offload_ctx *ntn_ctx)
{
struct ipa_ioc_add_hdr *hdr;
struct ipa_tx_intf tx;
struct ipa_rx_intf rx;
struct ipa_ioc_tx_intf_prop tx_prop[2];
struct ipa_ioc_rx_intf_prop rx_prop[2];
u32 len;
int ret = 0;
IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
inp->netdev_name);
memcpy(ntn_ctx->netdev_name, inp->netdev_name, IPA_RESOURCE_NAME_MAX);
ntn_ctx->hdr_len = inp->hdr_info[0].hdr_len;
ntn_ctx->notify = inp->notify;
ntn_ctx->priv = inp->priv;
/* add partial header */
len = sizeof(struct ipa_ioc_add_hdr) + 2 * sizeof(struct ipa_hdr_add);
hdr = kzalloc(len, GFP_KERNEL);
if (hdr == NULL) {
IPA_UC_OFFLOAD_ERR("fail to alloc %d bytes\n", len);
return -ENOMEM;
}
if (ipa_commit_partial_hdr(hdr, ntn_ctx->netdev_name, inp->hdr_info)) {
IPA_UC_OFFLOAD_ERR("fail to commit partial headers\n");
ret = -EFAULT;
goto fail;
}
/* populate tx prop */
tx.num_props = 2;
tx.prop = tx_prop;
memset(tx_prop, 0, sizeof(tx_prop));
tx_prop[0].ip = IPA_IP_v4;
tx_prop[0].dst_pipe = IPA_CLIENT_ODU_TETH_CONS;
tx_prop[0].hdr_l2_type = inp->hdr_info[0].hdr_type;
memcpy(tx_prop[0].hdr_name, hdr->hdr[IPA_IP_v4].name,
sizeof(tx_prop[0].hdr_name));
tx_prop[1].ip = IPA_IP_v6;
tx_prop[1].dst_pipe = IPA_CLIENT_ODU_TETH_CONS;
tx_prop[1].hdr_l2_type = inp->hdr_info[1].hdr_type;
memcpy(tx_prop[1].hdr_name, hdr->hdr[IPA_IP_v6].name,
sizeof(tx_prop[1].hdr_name));
/* populate rx prop */
rx.num_props = 2;
rx.prop = rx_prop;
memset(rx_prop, 0, sizeof(rx_prop));
rx_prop[0].ip = IPA_IP_v4;
rx_prop[0].src_pipe = IPA_CLIENT_ODU_PROD;
rx_prop[0].hdr_l2_type = inp->hdr_info[0].hdr_type;
if (inp->is_meta_data_valid) {
rx_prop[0].attrib.attrib_mask |= IPA_FLT_META_DATA;
rx_prop[0].attrib.meta_data = inp->meta_data;
rx_prop[0].attrib.meta_data_mask = inp->meta_data_mask;
}
rx_prop[1].ip = IPA_IP_v6;
rx_prop[1].src_pipe = IPA_CLIENT_ODU_PROD;
rx_prop[1].hdr_l2_type = inp->hdr_info[1].hdr_type;
if (inp->is_meta_data_valid) {
rx_prop[1].attrib.attrib_mask |= IPA_FLT_META_DATA;
rx_prop[1].attrib.meta_data = inp->meta_data;
rx_prop[1].attrib.meta_data_mask = inp->meta_data_mask;
}
if (ipa_register_intf(inp->netdev_name, &tx, &rx)) {
IPA_UC_OFFLOAD_ERR("fail to add interface prop\n");
memset(ntn_ctx, 0, sizeof(*ntn_ctx));
ret = -EFAULT;
goto fail;
}
ntn_ctx->partial_hdr_hdl[IPA_IP_v4] = hdr->hdr[IPA_IP_v4].hdr_hdl;
ntn_ctx->partial_hdr_hdl[IPA_IP_v6] = hdr->hdr[IPA_IP_v6].hdr_hdl;
init_completion(&ntn_ctx->ntn_completion);
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_INITIALIZED;
fail:
kfree(hdr);
return ret;
}
int ipa_uc_offload_reg_intf(
struct ipa_uc_offload_intf_params *inp,
struct ipa_uc_offload_out_params *outp)
{
struct ipa_uc_offload_ctx *ctx;
int ret = 0;
if (inp == NULL || outp == NULL) {
IPA_UC_OFFLOAD_ERR("invalid params in=%p out=%p\n", inp, outp);
return -EINVAL;
}
if (inp->proto <= IPA_UC_INVALID ||
inp->proto >= IPA_UC_MAX_PROT_SIZE) {
IPA_UC_OFFLOAD_ERR("invalid proto %d\n", inp->proto);
return -EINVAL;
}
if (!ipa_uc_offload_ctx[inp->proto]) {
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx == NULL) {
IPA_UC_OFFLOAD_ERR("fail to alloc uc offload ctx\n");
return -EFAULT;
}
ipa_uc_offload_ctx[inp->proto] = ctx;
ctx->proto = inp->proto;
} else
ctx = ipa_uc_offload_ctx[inp->proto];
if (ctx->state != IPA_UC_OFFLOAD_STATE_INVALID) {
IPA_UC_OFFLOAD_ERR("Already Initialized\n");
return -EINVAL;
}
if (ctx->proto == IPA_UC_NTN) {
ret = ipa_uc_offload_ntn_reg_intf(inp, outp, ctx);
if (!ret)
outp->clnt_hndl = IPA_UC_NTN;
}
return ret;
}
EXPORT_SYMBOL(ipa_uc_offload_reg_intf);
static int ipa_uc_ntn_cons_release(void)
{
return 0;
}
static int ipa_uc_ntn_cons_request(void)
{
int ret = 0;
struct ipa_uc_offload_ctx *ntn_ctx;
ntn_ctx = ipa_uc_offload_ctx[IPA_UC_NTN];
if (!ntn_ctx) {
IPA_UC_OFFLOAD_ERR("NTN is not initialized\n");
ret = -EFAULT;
} else if (ntn_ctx->state != IPA_UC_OFFLOAD_STATE_UP) {
IPA_UC_OFFLOAD_ERR("Invalid State: %d\n", ntn_ctx->state);
ret = -EFAULT;
}
return ret;
}
static void ipa_uc_offload_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
struct ipa_uc_offload_ctx *offload_ctx;
offload_ctx = (struct ipa_uc_offload_ctx *)user_data;
if (!(offload_ctx && offload_ctx->proto > IPA_UC_INVALID &&
offload_ctx->proto < IPA_UC_MAX_PROT_SIZE)) {
IPA_UC_OFFLOAD_ERR("Invalid user data\n");
return;
}
if (offload_ctx->state != IPA_UC_OFFLOAD_STATE_INITIALIZED)
IPA_UC_OFFLOAD_ERR("Invalid State: %d\n", offload_ctx->state);
switch (event) {
case IPA_RM_RESOURCE_GRANTED:
complete_all(&offload_ctx->ntn_completion);
break;
case IPA_RM_RESOURCE_RELEASED:
break;
default:
IPA_UC_OFFLOAD_ERR("Invalid RM Evt: %d", event);
break;
}
}
int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
struct ipa_ntn_conn_out_params *outp,
struct ipa_uc_offload_ctx *ntn_ctx)
{
struct ipa_rm_create_params param;
int result = 0;
if (inp->dl.ring_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT ||
inp->dl.buff_pool_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT) {
IPA_UC_OFFLOAD_ERR("alignment failure on TX\n");
return -EINVAL;
}
if (inp->ul.ring_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT ||
inp->ul.buff_pool_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT) {
IPA_UC_OFFLOAD_ERR("alignment failure on RX\n");
return -EINVAL;
}
memset(&param, 0, sizeof(param));
param.name = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
param.reg_params.user_data = ntn_ctx;
param.reg_params.notify_cb = ipa_uc_offload_rm_notify;
param.floor_voltage = IPA_VOLTAGE_SVS;
result = ipa_rm_create_resource(&param);
if (result) {
IPA_UC_OFFLOAD_ERR("fail to create ODU_ADAPT_PROD resource\n");
return -EFAULT;
}
memset(&param, 0, sizeof(param));
param.name = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
param.request_resource = ipa_uc_ntn_cons_request;
param.release_resource = ipa_uc_ntn_cons_release;
result = ipa_rm_create_resource(&param);
if (result) {
IPA_UC_OFFLOAD_ERR("fail to create ODU_ADAPT_CONS resource\n");
goto fail_create_rm_cons;
}
if (ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_APPS_CONS)) {
IPA_UC_OFFLOAD_ERR("fail to add rm dependency\n");
result = -EFAULT;
goto fail;
}
if (ipa_setup_uc_ntn_pipes(inp, ntn_ctx->notify,
ntn_ctx->priv, ntn_ctx->hdr_len, outp)) {
IPA_UC_OFFLOAD_ERR("fail to setup uc offload pipes\n");
result = -EFAULT;
goto fail;
}
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_UP;
result = ipa_rm_request_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
if (result == -EINPROGRESS) {
if (wait_for_completion_timeout(&ntn_ctx->ntn_completion,
10*HZ) == 0) {
IPA_UC_OFFLOAD_ERR("ODU PROD resource req time out\n");
result = -EFAULT;
goto fail;
}
} else if (result != 0) {
IPA_UC_OFFLOAD_ERR("fail to request resource\n");
result = -EFAULT;
goto fail;
}
return 0;
fail:
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS);
fail_create_rm_cons:
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
return result;
}
int ipa_uc_offload_conn_pipes(struct ipa_uc_offload_conn_in_params *inp,
struct ipa_uc_offload_conn_out_params *outp)
{
int ret = 0;
struct ipa_uc_offload_ctx *offload_ctx;
if (!(inp && outp)) {
IPA_UC_OFFLOAD_ERR("bad parm. in=%p out=%p\n", inp, outp);
return -EINVAL;
}
if (inp->clnt_hndl <= IPA_UC_INVALID ||
inp->clnt_hndl >= IPA_UC_MAX_PROT_SIZE) {
IPA_UC_OFFLOAD_ERR("invalid client handle %d\n",
inp->clnt_hndl);
return -EINVAL;
}
offload_ctx = ipa_uc_offload_ctx[inp->clnt_hndl];
if (!offload_ctx) {
IPA_UC_OFFLOAD_ERR("Invalid Handle\n");
return -EINVAL;
}
if (offload_ctx->state != IPA_UC_OFFLOAD_STATE_INITIALIZED) {
IPA_UC_OFFLOAD_ERR("Invalid state %d\n", offload_ctx->state);
return -EPERM;
}
switch (offload_ctx->proto) {
case IPA_UC_NTN:
ret = ipa_uc_ntn_conn_pipes(&inp->u.ntn, &outp->u.ntn,
offload_ctx);
break;
default:
IPA_UC_OFFLOAD_ERR("Invalid Proto :%d\n", offload_ctx->proto);
ret = -EINVAL;
break;
}
return ret;
}
EXPORT_SYMBOL(ipa_uc_offload_conn_pipes);
int ipa_set_perf_profile(struct ipa_perf_profile *profile)
{
struct ipa_rm_perf_profile rm_profile;
enum ipa_rm_resource_name resource_name;
if (profile == NULL) {
IPA_UC_OFFLOAD_ERR("Invalid input\n");
return -EINVAL;
}
rm_profile.max_supported_bandwidth_mbps =
profile->max_supported_bw_mbps;
if (profile->client == IPA_CLIENT_ODU_PROD) {
resource_name = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
} else if (profile->client == IPA_CLIENT_ODU_TETH_CONS) {
resource_name = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
} else {
IPA_UC_OFFLOAD_ERR("not supported\n");
return -EINVAL;
}
if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
IPA_UC_OFFLOAD_ERR("fail to setup rm perf profile\n");
return -EFAULT;
}
return 0;
}
EXPORT_SYMBOL(ipa_set_perf_profile);
static int ipa_uc_ntn_disconn_pipes(struct ipa_uc_offload_ctx *ntn_ctx)
{
int ipa_ep_idx_ul, ipa_ep_idx_dl;
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_DOWN;
if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_APPS_CONS)) {
IPA_UC_OFFLOAD_ERR("fail to delete rm dependency\n");
return -EFAULT;
}
if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD)) {
IPA_UC_OFFLOAD_ERR("fail to delete ODU_ADAPT_PROD resource\n");
return -EFAULT;
}
if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS)) {
IPA_UC_OFFLOAD_ERR("fail to delete ODU_ADAPT_CONS resource\n");
return -EFAULT;
}
ipa_ep_idx_ul = ipa_get_ep_mapping(IPA_CLIENT_ODU_PROD);
ipa_ep_idx_dl = ipa_get_ep_mapping(IPA_CLIENT_ODU_TETH_CONS);
if (ipa_tear_down_uc_offload_pipes(ipa_ep_idx_ul, ipa_ep_idx_dl)) {
IPA_UC_OFFLOAD_ERR("fail to tear down uc offload pipes\n");
return -EFAULT;
}
return 0;
}
int ipa_uc_offload_disconn_pipes(u32 clnt_hdl)
{
struct ipa_uc_offload_ctx *offload_ctx;
int ret = 0;
if (clnt_hdl <= IPA_UC_INVALID ||
clnt_hdl >= IPA_UC_MAX_PROT_SIZE) {
IPA_UC_OFFLOAD_ERR("Invalid client handle %d\n", clnt_hdl);
return -EINVAL;
}
offload_ctx = ipa_uc_offload_ctx[clnt_hdl];
if (!offload_ctx) {
IPA_UC_OFFLOAD_ERR("Invalid client Handle\n");
return -EINVAL;
}
if (offload_ctx->state != IPA_UC_OFFLOAD_STATE_UP) {
IPA_UC_OFFLOAD_ERR("Invalid state\n");
return -EINVAL;
}
switch (offload_ctx->proto) {
case IPA_UC_NTN:
ret = ipa_uc_ntn_disconn_pipes(offload_ctx);
break;
default:
IPA_UC_OFFLOAD_ERR("Invalid Proto :%d\n", clnt_hdl);
ret = -EINVAL;
break;
}
return ret;
}
EXPORT_SYMBOL(ipa_uc_offload_disconn_pipes);
static int ipa_uc_ntn_cleanup(struct ipa_uc_offload_ctx *ntn_ctx)
{
int len, result = 0;
struct ipa_ioc_del_hdr *hdr;
len = sizeof(struct ipa_ioc_del_hdr) + 2 * sizeof(struct ipa_hdr_del);
hdr = kzalloc(len, GFP_KERNEL);
if (hdr == NULL) {
IPA_UC_OFFLOAD_ERR("fail to alloc %d bytes\n", len);
return -ENOMEM;
}
hdr->commit = 1;
hdr->num_hdls = 2;
hdr->hdl[0].hdl = ntn_ctx->partial_hdr_hdl[0];
hdr->hdl[1].hdl = ntn_ctx->partial_hdr_hdl[1];
if (ipa_del_hdr(hdr)) {
IPA_UC_OFFLOAD_ERR("fail to delete partial header\n");
result = -EFAULT;
goto fail;
}
if (ipa_deregister_intf(ntn_ctx->netdev_name)) {
IPA_UC_OFFLOAD_ERR("fail to delete interface prop\n");
result = -EFAULT;
goto fail;
}
fail:
kfree(hdr);
return result;
}
int ipa_uc_offload_cleanup(u32 clnt_hdl)
{
struct ipa_uc_offload_ctx *offload_ctx;
int ret = 0;
if (clnt_hdl <= IPA_UC_INVALID ||
clnt_hdl >= IPA_UC_MAX_PROT_SIZE) {
IPA_UC_OFFLOAD_ERR("Invalid client handle %d\n", clnt_hdl);
return -EINVAL;
}
offload_ctx = ipa_uc_offload_ctx[clnt_hdl];
if (!offload_ctx) {
IPA_UC_OFFLOAD_ERR("Invalid client handle %d\n", clnt_hdl);
return -EINVAL;
}
if (offload_ctx->state != IPA_UC_OFFLOAD_STATE_DOWN) {
IPA_UC_OFFLOAD_ERR("Invalid State %d\n", offload_ctx->state);
return -EINVAL;
}
switch (offload_ctx->proto) {
case IPA_UC_NTN:
ret = ipa_uc_ntn_cleanup(offload_ctx);
break;
default:
IPA_UC_OFFLOAD_ERR("Invalid Proto :%d\n", clnt_hdl);
ret = -EINVAL;
break;
}
if (!ret) {
kfree(offload_ctx);
offload_ctx = NULL;
ipa_uc_offload_ctx[clnt_hdl] = NULL;
}
return ret;
}
EXPORT_SYMBOL(ipa_uc_offload_cleanup);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,383 @@
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/ipa_mhi.h>
#include <linux/ipa_qmi_service_v01.h>
#ifndef _IPA_COMMON_I_H_
#define _IPA_COMMON_I_H_
#include <linux/ipc_logging.h>
#include <linux/ipa.h>
#include <linux/ipa_uc_offload.h>
#define __FILENAME__ \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client) \
log_info.file = __FILENAME__; \
log_info.line = __LINE__; \
log_info.type = EP; \
log_info.id_string = ipa_clients_strings[client]
#define IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info) \
log_info.file = __FILENAME__; \
log_info.line = __LINE__; \
log_info.type = SIMPLE; \
log_info.id_string = __func__
#define IPA_ACTIVE_CLIENTS_PREP_RESOURCE(log_info, resource_name) \
log_info.file = __FILENAME__; \
log_info.line = __LINE__; \
log_info.type = RESOURCE; \
log_info.id_string = resource_name
#define IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, id_str) \
log_info.file = __FILENAME__; \
log_info.line = __LINE__; \
log_info.type = SPECIAL; \
log_info.id_string = id_str
#define IPA_ACTIVE_CLIENTS_INC_EP(client) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client); \
ipa_inc_client_enable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_DEC_EP(client) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client); \
ipa_dec_client_disable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_INC_SIMPLE() \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info); \
ipa_inc_client_enable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_DEC_SIMPLE() \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info); \
ipa_dec_client_disable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_INC_RESOURCE(resource_name) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_RESOURCE(log_info, resource_name); \
ipa_inc_client_enable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_DEC_RESOURCE(resource_name) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_RESOURCE(log_info, resource_name); \
ipa_dec_client_disable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_INC_SPECIAL(id_str) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, id_str); \
ipa_inc_client_enable_clks(&log_info); \
} while (0)
#define IPA_ACTIVE_CLIENTS_DEC_SPECIAL(id_str) \
do { \
struct ipa_active_client_logging_info log_info; \
IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, id_str); \
ipa_dec_client_disable_clks(&log_info); \
} while (0)
#define ipa_assert_on(condition)\
do {\
if (unlikely(condition))\
ipa_assert();\
} while (0)
#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)
enum ipa_active_client_log_type {
EP,
SIMPLE,
RESOURCE,
SPECIAL,
INVALID
};
struct ipa_active_client_logging_info {
const char *id_string;
char *file;
int line;
enum ipa_active_client_log_type type;
};
/**
* struct ipa_mem_buffer - IPA memory buffer
* @base: base
* @phys_base: physical base address
* @size: size of memory buffer
*/
struct ipa_mem_buffer {
void *base;
dma_addr_t phys_base;
u32 size;
};
#define IPA_MHI_GSI_ER_START 10
#define IPA_MHI_GSI_ER_END 16
/**
* enum ipa3_mhi_burst_mode - MHI channel burst mode state
*
* Values are according to MHI specification
* @IPA_MHI_BURST_MODE_DEFAULT: burst mode enabled for HW channels,
* disabled for SW channels
* @IPA_MHI_BURST_MODE_RESERVED:
* @IPA_MHI_BURST_MODE_DISABLE: Burst mode is disabled for this channel
* @IPA_MHI_BURST_MODE_ENABLE: Burst mode is enabled for this channel
*
*/
enum ipa3_mhi_burst_mode {
IPA_MHI_BURST_MODE_DEFAULT,
IPA_MHI_BURST_MODE_RESERVED,
IPA_MHI_BURST_MODE_DISABLE,
IPA_MHI_BURST_MODE_ENABLE,
};
/**
* enum ipa_hw_mhi_channel_states - MHI channel state machine
*
* Values are according to MHI specification
* @IPA_HW_MHI_CHANNEL_STATE_DISABLE: Channel is disabled and not processed by
* the host or device.
* @IPA_HW_MHI_CHANNEL_STATE_ENABLE: A channel is enabled after being
* initialized and configured by host, including its channel context and
* associated transfer ring. While this state, the channel is not active
* and the device does not process transfer.
* @IPA_HW_MHI_CHANNEL_STATE_RUN: The device processes transfers and doorbell
* for channels.
* @IPA_HW_MHI_CHANNEL_STATE_SUSPEND: Used to halt operations on the channel.
* The device does not process transfers for the channel in this state.
* This state is typically used to synchronize the transition to low power
* modes.
* @IPA_HW_MHI_CHANNEL_STATE_STOP: Used to halt operations on the channel.
* The device does not process transfers for the channel in this state.
* @IPA_HW_MHI_CHANNEL_STATE_ERROR: The device detected an error in an element
* from the transfer ring associated with the channel.
* @IPA_HW_MHI_CHANNEL_STATE_INVALID: Invalid state. Shall not be in use in
* operational scenario.
*/
enum ipa_hw_mhi_channel_states {
IPA_HW_MHI_CHANNEL_STATE_DISABLE = 0,
IPA_HW_MHI_CHANNEL_STATE_ENABLE = 1,
IPA_HW_MHI_CHANNEL_STATE_RUN = 2,
IPA_HW_MHI_CHANNEL_STATE_SUSPEND = 3,
IPA_HW_MHI_CHANNEL_STATE_STOP = 4,
IPA_HW_MHI_CHANNEL_STATE_ERROR = 5,
IPA_HW_MHI_CHANNEL_STATE_INVALID = 0xFF
};
/**
* Structure holding the parameters for IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO
* command. Parameters are sent as 32b immediate parameters.
* @isDlUlSyncEnabled: Flag to indicate if DL UL Syncronization is enabled
* @UlAccmVal: UL Timer Accumulation value (Period after which device will poll
* for UL data)
* @ulMsiEventThreshold: Threshold at which HW fires MSI to host for UL events
* @dlMsiEventThreshold: Threshold at which HW fires MSI to host for DL events
*/
union IpaHwMhiDlUlSyncCmdData_t {
struct IpaHwMhiDlUlSyncCmdParams_t {
u32 isDlUlSyncEnabled:8;
u32 UlAccmVal:8;
u32 ulMsiEventThreshold:8;
u32 dlMsiEventThreshold:8;
} params;
u32 raw32b;
};
struct ipa_mhi_ch_ctx {
u8 chstate;/*0-7*/
u8 brstmode:2;/*8-9*/
u8 pollcfg:6;/*10-15*/
u16 rsvd;/*16-31*/
u32 chtype;
u32 erindex;
u64 rbase;
u64 rlen;
u64 rp;
u64 wp;
} __packed;
struct ipa_mhi_ev_ctx {
u32 intmodc:16;
u32 intmodt:16;
u32 ertype;
u32 msivec;
u64 rbase;
u64 rlen;
u64 rp;
u64 wp;
} __packed;
struct ipa_mhi_init_uc_engine {
struct ipa_mhi_msi_info *msi;
u32 mmio_addr;
u32 host_ctrl_addr;
u32 host_data_addr;
u32 first_ch_idx;
u32 first_er_idx;
union IpaHwMhiDlUlSyncCmdData_t *ipa_cached_dl_ul_sync_info;
};
struct ipa_mhi_init_gsi_engine {
u32 first_ch_idx;
};
struct ipa_mhi_init_engine {
struct ipa_mhi_init_uc_engine uC;
struct ipa_mhi_init_gsi_engine gsi;
};
struct start_gsi_channel {
enum ipa_hw_mhi_channel_states state;
struct ipa_mhi_msi_info *msi;
struct ipa_mhi_ev_ctx *ev_ctx_host;
u64 event_context_addr;
struct ipa_mhi_ch_ctx *ch_ctx_host;
u64 channel_context_addr;
void (*ch_err_cb)(struct gsi_chan_err_notify *notify);
void (*ev_err_cb)(struct gsi_evt_err_notify *notify);
void *channel;
bool assert_bit40;
struct gsi_mhi_channel_scratch *mhi;
unsigned long *cached_gsi_evt_ring_hdl;
uint8_t evchid;
};
struct start_uc_channel {
enum ipa_hw_mhi_channel_states state;
u8 index;
u8 id;
};
struct start_mhi_channel {
struct start_uc_channel uC;
struct start_gsi_channel gsi;
};
struct ipa_mhi_connect_params_internal {
struct ipa_sys_connect_params *sys;
u8 channel_id;
struct start_mhi_channel start;
};
/**
* struct ipa_hdr_offset_entry - IPA header offset entry
* @link: entry's link in global header offset entries list
* @offset: the offset
* @bin: bin
*/
struct ipa_hdr_offset_entry {
struct list_head link;
u32 offset;
u32 bin;
};
extern const char *ipa_clients_strings[];
#define IPA_IPC_LOGGING(buf, fmt, args...) \
do { \
if (buf) \
ipc_log_string((buf), fmt, __func__, __LINE__, \
## args); \
} while (0)
void ipa_inc_client_enable_clks(struct ipa_active_client_logging_info *id);
void ipa_dec_client_disable_clks(struct ipa_active_client_logging_info *id);
int ipa_inc_client_enable_clks_no_block(
struct ipa_active_client_logging_info *id);
int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource);
int ipa_resume_resource(enum ipa_rm_resource_name name);
int ipa_suspend_resource_sync(enum ipa_rm_resource_name resource);
int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
u32 bandwidth_mbps);
void *ipa_get_ipc_logbuf(void);
void *ipa_get_ipc_logbuf_low(void);
void ipa_assert(void);
/* MHI */
int ipa_mhi_init_engine(struct ipa_mhi_init_engine *params);
int ipa_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
u32 *clnt_hdl);
int ipa_disconnect_mhi_pipe(u32 clnt_hdl);
bool ipa_mhi_stop_gsi_channel(enum ipa_client_type client);
int ipa_qmi_enable_force_clear_datapath_send(
struct ipa_enable_force_clear_datapath_req_msg_v01 *req);
int ipa_qmi_disable_force_clear_datapath_send(
struct ipa_disable_force_clear_datapath_req_msg_v01 *req);
int ipa_generate_tag_process(void);
int ipa_disable_sps_pipe(enum ipa_client_type client);
int ipa_mhi_reset_channel_internal(enum ipa_client_type client);
int ipa_mhi_start_channel_internal(enum ipa_client_type client);
bool ipa_mhi_sps_channel_empty(enum ipa_client_type client);
int ipa_mhi_resume_channels_internal(enum ipa_client_type client,
bool LPTransitionRejected, bool brstmode_enabled,
union __packed gsi_channel_scratch ch_scratch, u8 index);
int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
int ipa_mhi_query_ch_info(enum ipa_client_type client,
struct gsi_chan_info *ch_info);
int ipa_mhi_destroy_channel(enum ipa_client_type client);
int ipa_mhi_is_using_dma(bool *flag);
const char *ipa_mhi_get_state_str(int state);
/* MHI uC */
int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd);
int ipa_uc_mhi_init
(void (*ready_cb)(void), void (*wakeup_request_cb)(void));
void ipa_uc_mhi_cleanup(void);
int ipa_uc_mhi_reset_channel(int channelHandle);
int ipa_uc_mhi_suspend_channel(int channelHandle);
int ipa_uc_mhi_stop_event_update_channel(int channelHandle);
int ipa_uc_mhi_print_stats(char *dbg_buff, int size);
/* uC */
int ipa_uc_state_check(void);
/* general */
void ipa_get_holb(int ep_idx, struct ipa_ep_cfg_holb *holb);
void ipa_set_tag_process_before_gating(bool val);
bool ipa_has_open_aggr_frame(enum ipa_client_type client);
int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
ipa_notify_cb notify, void *priv, u8 hdr_len,
struct ipa_ntn_conn_out_params *outp);
int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
u8 *ipa_write_64(u64 w, u8 *dest);
u8 *ipa_write_32(u32 w, u8 *dest);
u8 *ipa_write_16(u16 hw, u8 *dest);
u8 *ipa_write_8(u8 b, u8 *dest);
u8 *ipa_pad_to_64(u8 *dest);
u8 *ipa_pad_to_32(u8 *dest);
const char *ipa_get_version_string(enum ipa_hw_type ver);
#endif /* _IPA_COMMON_I_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,251 @@
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/slab.h>
#include "ipa_rm_dependency_graph.h"
#include "ipa_rm_i.h"
static int ipa_rm_dep_get_index(enum ipa_rm_resource_name resource_name)
{
int resource_index = IPA_RM_INDEX_INVALID;
if (IPA_RM_RESORCE_IS_PROD(resource_name))
resource_index = ipa_rm_prod_index(resource_name);
else if (IPA_RM_RESORCE_IS_CONS(resource_name))
resource_index = ipa_rm_cons_index(resource_name);
return resource_index;
}
/**
* ipa_rm_dep_graph_create() - creates graph
* @dep_graph: [out] created dependency graph
*
* Returns: dependency graph on success, NULL on failure
*/
int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph)
{
int result = 0;
*dep_graph = kzalloc(sizeof(**dep_graph), GFP_KERNEL);
if (!*dep_graph) {
IPA_RM_ERR("no mem\n");
result = -ENOMEM;
goto bail;
}
bail:
return result;
}
/**
* ipa_rm_dep_graph_delete() - destroyes the graph
* @graph: [in] dependency graph
*
* Frees all resources.
*/
void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph)
{
int resource_index;
if (!graph) {
IPA_RM_ERR("invalid params\n");
return;
}
for (resource_index = 0;
resource_index < IPA_RM_RESOURCE_MAX;
resource_index++)
kfree(graph->resource_table[resource_index]);
memset(graph->resource_table, 0, sizeof(graph->resource_table));
}
/**
* ipa_rm_dep_graph_get_resource() - provides a resource by name
* @graph: [in] dependency graph
* @name: [in] name of the resource
* @resource: [out] resource in case of success
*
* Returns: 0 on success, negative on failure
*/
int ipa_rm_dep_graph_get_resource(
struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
struct ipa_rm_resource **resource)
{
int result;
int resource_index;
if (!graph) {
result = -EINVAL;
goto bail;
}
resource_index = ipa_rm_dep_get_index(resource_name);
if (resource_index == IPA_RM_INDEX_INVALID) {
result = -EINVAL;
goto bail;
}
*resource = graph->resource_table[resource_index];
if (!*resource) {
result = -EINVAL;
goto bail;
}
result = 0;
bail:
return result;
}
/**
* ipa_rm_dep_graph_add() - adds resource to graph
* @graph: [in] dependency graph
* @resource: [in] resource to add
*
* Returns: 0 on success, negative on failure
*/
int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
struct ipa_rm_resource *resource)
{
int result = 0;
int resource_index;
if (!graph || !resource) {
result = -EINVAL;
goto bail;
}
resource_index = ipa_rm_dep_get_index(resource->name);
if (resource_index == IPA_RM_INDEX_INVALID) {
result = -EINVAL;
goto bail;
}
graph->resource_table[resource_index] = resource;
bail:
return result;
}
/**
* ipa_rm_dep_graph_remove() - removes resource from graph
* @graph: [in] dependency graph
* @resource: [in] resource to add
*
* Returns: 0 on success, negative on failure
*/
int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name)
{
if (!graph)
return -EINVAL;
graph->resource_table[resource_name] = NULL;
return 0;
}
/**
* ipa_rm_dep_graph_add_dependency() - adds dependency between
* two nodes in graph
* @graph: [in] dependency graph
* @resource_name: [in] resource to add
* @depends_on_name: [in] resource to add
* @userspace_dep: [in] operation requested by userspace ?
*
* Returns: 0 on success, negative on failure
*/
int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name,
bool userspace_dep)
{
struct ipa_rm_resource *dependent = NULL;
struct ipa_rm_resource *dependency = NULL;
int result;
if (!graph ||
!IPA_RM_RESORCE_IS_PROD(resource_name) ||
!IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
IPA_RM_ERR("invalid params\n");
result = -EINVAL;
goto bail;
}
if (ipa_rm_dep_graph_get_resource(graph,
resource_name,
&dependent)) {
IPA_RM_ERR("%s does not exist\n",
ipa_rm_resource_str(resource_name));
result = -EINVAL;
goto bail;
}
if (ipa_rm_dep_graph_get_resource(graph,
depends_on_name,
&dependency)) {
IPA_RM_ERR("%s does not exist\n",
ipa_rm_resource_str(depends_on_name));
result = -EINVAL;
goto bail;
}
result = ipa_rm_resource_add_dependency(dependent, dependency,
userspace_dep);
bail:
IPA_RM_DBG("EXIT with %d\n", result);
return result;
}
/**
* ipa_rm_dep_graph_delete_dependency() - deleted dependency between
* two nodes in graph
* @graph: [in] dependency graph
* @resource_name: [in] resource to delete
* @depends_on_name: [in] resource to delete
* @userspace_dep: [in] operation requested by userspace ?
*
* Returns: 0 on success, negative on failure
*
*/
int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name,
bool userspace_dep)
{
struct ipa_rm_resource *dependent = NULL;
struct ipa_rm_resource *dependency = NULL;
int result;
if (!graph ||
!IPA_RM_RESORCE_IS_PROD(resource_name) ||
!IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
IPA_RM_ERR("invalid params\n");
result = -EINVAL;
goto bail;
}
if (ipa_rm_dep_graph_get_resource(graph,
resource_name,
&dependent)) {
IPA_RM_ERR("%s does not exist\n",
ipa_rm_resource_str(resource_name));
result = -EINVAL;
goto bail;
}
if (ipa_rm_dep_graph_get_resource(graph,
depends_on_name,
&dependency)) {
IPA_RM_ERR("%s does not exist\n",
ipa_rm_resource_str(depends_on_name));
result = -EINVAL;
goto bail;
}
result = ipa_rm_resource_delete_dependency(dependent, dependency,
userspace_dep);
bail:
IPA_RM_DBG("EXIT with %d\n", result);
return result;
}

View file

@ -0,0 +1,49 @@
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _IPA_RM_DEPENDENCY_GRAPH_H_
#define _IPA_RM_DEPENDENCY_GRAPH_H_
#include <linux/list.h>
#include <linux/ipa.h>
#include "ipa_rm_resource.h"
struct ipa_rm_dep_graph {
struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
};
int ipa_rm_dep_graph_get_resource(
struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name name,
struct ipa_rm_resource **resource);
int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph);
void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph);
int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
struct ipa_rm_resource *resource);
int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name);
int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name,
bool userspsace_dep);
int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name,
bool userspsace_dep);
#endif /* _IPA_RM_DEPENDENCY_GRAPH_H_ */

View file

@ -0,0 +1,157 @@
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _IPA_RM_I_H_
#define _IPA_RM_I_H_
#include <linux/workqueue.h>
#include <linux/ipa.h>
#include "ipa_rm_resource.h"
#include "ipa_common_i.h"
#define IPA_RM_DRV_NAME "ipa_rm"
#define IPA_RM_DBG_LOW(fmt, args...) \
do { \
pr_debug(IPA_RM_DRV_NAME " %s:%d " fmt, __func__, __LINE__, \
## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_RM_DBG(fmt, args...) \
do { \
pr_debug(IPA_RM_DRV_NAME " %s:%d " fmt, __func__, __LINE__, \
## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_RM_ERR(fmt, args...) \
do { \
pr_err(IPA_RM_DRV_NAME " %s:%d " fmt, __func__, __LINE__, \
## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_RM_RESOURCE_CONS_MAX \
(IPA_RM_RESOURCE_MAX - IPA_RM_RESOURCE_PROD_MAX)
#define IPA_RM_RESORCE_IS_PROD(x) \
(x >= IPA_RM_RESOURCE_PROD && x < IPA_RM_RESOURCE_PROD_MAX)
#define IPA_RM_RESORCE_IS_CONS(x) \
(x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX)
#define IPA_RM_INDEX_INVALID (-1)
#define IPA_RM_RELEASE_DELAY_IN_MSEC 1000
int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name);
int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name);
/**
* struct ipa_rm_delayed_release_work_type - IPA RM delayed resource release
* work type
* @delayed_work: work struct
* @ipa_rm_resource_name: name of the resource on which this work should be done
* @needed_bw: bandwidth required for resource in Mbps
* @dec_usage_count: decrease usage count on release ?
*/
struct ipa_rm_delayed_release_work_type {
struct delayed_work work;
enum ipa_rm_resource_name resource_name;
u32 needed_bw;
bool dec_usage_count;
};
/**
* enum ipa_rm_wq_cmd - workqueue commands
*/
enum ipa_rm_wq_cmd {
IPA_RM_WQ_NOTIFY_PROD,
IPA_RM_WQ_NOTIFY_CONS,
IPA_RM_WQ_RESOURCE_CB
};
/**
* struct ipa_rm_wq_work_type - IPA RM worqueue specific
* work type
* @work: work struct
* @wq_cmd: command that should be processed in workqueue context
* @resource_name: name of the resource on which this work
* should be done
* @dep_graph: data structure to search for resource if exists
* @event: event to notify
* @notify_registered_only: notify only clients registered by
* ipa_rm_register()
*/
struct ipa_rm_wq_work_type {
struct work_struct work;
enum ipa_rm_wq_cmd wq_cmd;
enum ipa_rm_resource_name resource_name;
enum ipa_rm_event event;
bool notify_registered_only;
};
/**
* struct ipa_rm_wq_suspend_resume_work_type - IPA RM worqueue resume or
* suspend work type
* @work: work struct
* @resource_name: name of the resource on which this work
* should be done
* @prev_state:
* @needed_bw:
*/
struct ipa_rm_wq_suspend_resume_work_type {
struct work_struct work;
enum ipa_rm_resource_name resource_name;
enum ipa_rm_resource_state prev_state;
u32 needed_bw;
};
int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_event event,
bool notify_registered_only);
int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_state prev_state,
u32 needed_bw);
int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_state prev_state,
u32 needed_bw);
int ipa_rm_initialize(void);
int ipa_rm_stat(char *buf, int size);
const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name);
void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name);
int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name);
void delayed_release_work_func(struct work_struct *work);
int ipa_rm_add_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name);
int ipa_rm_delete_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name);
void ipa_rm_exit(void);
#endif /* _IPA_RM_I_H_ */

Some files were not shown because too many files have changed in this diff Show more