Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 846af39b authored by Mayank Rana's avatar Mayank Rana
Browse files

dwc3-msm: Map IPA channel doorbell address with USB device



USB controller needs to ring doorbell to IPA channel. When USB
SMMU stage S1 is enabled, it is must to map IPA channel related
doorbell address with USB device context bank otherwise unmapped
SMMU access related page fault is seen when USB controller tries
to ring the doorbell.

Change-Id: Ic624a9d6b2c0b106edda6a80aafa804bc3051bf9
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 436b6888
Loading
Loading
Loading
Loading
+30 −14
Original line number Diff line number Diff line
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, 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
@@ -121,7 +121,7 @@ MODULE_PARM_DESC(override_usb_speed, "override for USB speed");
#define GSI_DBL_ADDR_L(n)	((QSCRATCH_REG_OFFSET + 0x110) + (n*4))
#define GSI_DBL_ADDR_H(n)	((QSCRATCH_REG_OFFSET + 0x120) + (n*4))
#define GSI_RING_BASE_ADDR_L(n)	((QSCRATCH_REG_OFFSET + 0x130) + (n*4))
#define GSI_RING_BASE_ADDR_H(n)	((QSCRATCH_REG_OFFSET + 0x140) + (n*4))
#define GSI_RING_BASE_ADDR_H(n)	((QSCRATCH_REG_OFFSET + 0x144) + (n*4))

#define	GSI_IF_STS	(QSCRATCH_REG_OFFSET + 0x1A4)
#define	GSI_WR_CTRL_STATE_MASK	BIT(15)
@@ -933,9 +933,10 @@ static int gsi_startxfer_for_ep(struct usb_ep *ep)
* for GSI channel creation.
*
* @usb_ep - pointer to usb_ep instance.
* @dbl_addr - Doorbell address obtained from IPA driver
* @request - USB GSI request to get Doorbell address obtained from IPA driver
*/
static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, u32 dbl_addr)
static void gsi_store_ringbase_dbl_info(struct usb_ep *ep,
			struct usb_gsi_request *request)
{
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3	*dwc = dep->dwc;
@@ -944,11 +945,27 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, u32 dbl_addr)

	dwc3_msm_write_reg(mdwc->base, GSI_RING_BASE_ADDR_L(n),
			dwc3_trb_dma_offset(dep, &dep->trb_pool[0]));
	dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(n), dbl_addr);

	dev_dbg(mdwc->dev, "Ring Base Addr %d = %x", n,
	if (request->mapped_db_reg_phs_addr_lsb)
		dma_unmap_resource(dwc->sysdev,
			request->mapped_db_reg_phs_addr_lsb,
			PAGE_SIZE, DMA_BIDIRECTIONAL, 0);

	request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev,
			(phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE,
			DMA_BIDIRECTIONAL, 0);
	if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb))
		dev_err(mdwc->dev, "mapping error for db_reg_phs_addr_lsb\n");

	dev_dbg(mdwc->dev, "ep:%s dbl_addr_lsb:%x mapped_dbl_addr_lsb:%llx\n",
		ep->name, request->db_reg_phs_addr_lsb,
		(unsigned long long)request->mapped_db_reg_phs_addr_lsb);

	dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(n),
			(u32)request->mapped_db_reg_phs_addr_lsb);
	dev_dbg(mdwc->dev, "Ring Base Addr %d: %x (LSB)\n", n,
			dwc3_msm_read_reg(mdwc->base, GSI_RING_BASE_ADDR_L(n)));
	dev_dbg(mdwc->dev, "GSI DB Addr %d = %x", n,
	dev_dbg(mdwc->dev, "GSI DB Addr %d: %x (LSB)\n", n,
			dwc3_msm_read_reg(mdwc->base, GSI_DBL_ADDR_L(n)));
}

@@ -964,9 +981,6 @@ static void gsi_ring_db(struct usb_ep *ep, struct usb_gsi_request *request)
	void __iomem *gsi_dbl_address_lsb;
	void __iomem *gsi_dbl_address_msb;
	dma_addr_t offset;
	u64 dbl_addr = *((u64 *)request->buf_base_addr);
	u32 dbl_lo_addr = (dbl_addr & 0xFFFFFFFF);
	u32 dbl_hi_addr = (dbl_addr >> 32);
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3	*dwc = dep->dwc;
	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
@@ -974,18 +988,19 @@ static void gsi_ring_db(struct usb_ep *ep, struct usb_gsi_request *request)
					: (request->num_bufs + 2);

	gsi_dbl_address_lsb = devm_ioremap_nocache(mdwc->dev,
					dbl_lo_addr, sizeof(u32));
				request->db_reg_phs_addr_lsb, sizeof(u32));
	if (!gsi_dbl_address_lsb)
		dev_dbg(mdwc->dev, "Failed to get GSI DBL address LSB\n");

	gsi_dbl_address_msb = devm_ioremap_nocache(mdwc->dev,
					dbl_hi_addr, sizeof(u32));
			request->db_reg_phs_addr_msb, sizeof(u32));
	if (!gsi_dbl_address_msb)
		dev_dbg(mdwc->dev, "Failed to get GSI DBL address MSB\n");

	offset = dwc3_trb_dma_offset(dep, &dep->trb_pool[num_trbs-1]);
	dev_dbg(mdwc->dev, "Writing link TRB addr: %pa to %p (%x) for ep:%s\n",
		&offset, gsi_dbl_address_lsb, dbl_lo_addr, ep->name);
		&offset, gsi_dbl_address_lsb, request->db_reg_phs_addr_lsb,
		ep->name);

	writel_relaxed(offset, gsi_dbl_address_lsb);
	writel_relaxed(0, gsi_dbl_address_msb);
@@ -1381,7 +1396,8 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
		break;
	case GSI_EP_OP_STORE_DBL_INFO:
		dev_dbg(mdwc->dev, "EP_OP_STORE_DBL_INFO\n");
		gsi_store_ringbase_dbl_info(ep, *((u32 *)op_data));
		request = (struct usb_gsi_request *)op_data;
		gsi_store_ringbase_dbl_info(ep, request);
		break;
	case GSI_EP_OP_ENABLE_GSI:
		dev_dbg(mdwc->dev, "EP_OP_ENABLE_GSI\n");
+22 −40
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2017, Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2018, 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
@@ -407,17 +407,17 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
			ipa_out_channel_out_params.db_reg_phs_addr_lsb);

	d_port->in_channel_handle = ipa_in_channel_out_params.clnt_hdl;
	d_port->in_db_reg_phs_addr_lsb =
	d_port->in_request.db_reg_phs_addr_lsb =
		ipa_in_channel_out_params.db_reg_phs_addr_lsb;
	d_port->in_db_reg_phs_addr_msb =
	d_port->in_request.db_reg_phs_addr_msb =
		ipa_in_channel_out_params.db_reg_phs_addr_msb;

	if (gsi->prot_id != IPA_USB_DIAG) {
		d_port->out_channel_handle =
			ipa_out_channel_out_params.clnt_hdl;
		d_port->out_db_reg_phs_addr_lsb =
		d_port->out_request.db_reg_phs_addr_lsb =
			ipa_out_channel_out_params.db_reg_phs_addr_lsb;
		d_port->out_db_reg_phs_addr_msb =
		d_port->out_request.db_reg_phs_addr_msb =
			ipa_out_channel_out_params.db_reg_phs_addr_msb;
	}
	return ret;
@@ -426,22 +426,19 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
static void ipa_data_path_enable(struct gsi_data_port *d_port)
{
	struct f_gsi *gsi = d_port_to_gsi(d_port);
	struct usb_gsi_request req;
	u64 dbl_register_addr;
	bool block_db = false;


	log_event_dbg("in_db_reg_phs_addr_lsb = %x",
			gsi->d_port.in_db_reg_phs_addr_lsb);
	log_event_dbg("IN: db_reg_phs_addr_lsb = %x",
			gsi->d_port.in_request.db_reg_phs_addr_lsb);
	usb_gsi_ep_op(gsi->d_port.in_ep,
			(void *)&gsi->d_port.in_db_reg_phs_addr_lsb,
			&gsi->d_port.in_request,
			GSI_EP_OP_STORE_DBL_INFO);

	if (gsi->d_port.out_ep) {
		log_event_dbg("out_db_reg_phs_addr_lsb = %x",
				gsi->d_port.out_db_reg_phs_addr_lsb);
		log_event_dbg("OUT: db_reg_phs_addr_lsb = %x",
				gsi->d_port.out_request.db_reg_phs_addr_lsb);
		usb_gsi_ep_op(gsi->d_port.out_ep,
				(void *)&gsi->d_port.out_db_reg_phs_addr_lsb,
				&gsi->d_port.out_request,
				GSI_EP_OP_STORE_DBL_INFO);

		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
@@ -452,29 +449,12 @@ static void ipa_data_path_enable(struct gsi_data_port *d_port)
	usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
				GSI_EP_OP_SET_CLR_BLOCK_DBL);

	/* GSI channel DBL address for USB IN endpoint */
	dbl_register_addr = gsi->d_port.in_db_reg_phs_addr_msb;
	dbl_register_addr = dbl_register_addr << 32;
	dbl_register_addr =
		dbl_register_addr | gsi->d_port.in_db_reg_phs_addr_lsb;
	usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
						GSI_EP_OP_RING_DB);

	/* use temp gsi request to pass 64 bit dbl reg addr and num_bufs */
	req.buf_base_addr = &dbl_register_addr;

	req.num_bufs = gsi->d_port.in_request.num_bufs;
	usb_gsi_ep_op(gsi->d_port.in_ep, &req, GSI_EP_OP_RING_DB);

	if (gsi->d_port.out_ep) {
		/* GSI channel DBL address for USB OUT endpoint */
		dbl_register_addr = gsi->d_port.out_db_reg_phs_addr_msb;
		dbl_register_addr = dbl_register_addr << 32;
		dbl_register_addr = dbl_register_addr |
					gsi->d_port.out_db_reg_phs_addr_lsb;
		/* use temp request to pass 64 bit dbl reg addr and num_bufs */
		req.buf_base_addr = &dbl_register_addr;
		req.num_bufs = gsi->d_port.out_request.num_bufs;
		usb_gsi_ep_op(gsi->d_port.out_ep, &req, GSI_EP_OP_RING_DB);
	}
	if (gsi->d_port.out_ep)
		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
						GSI_EP_OP_RING_DB);
}

static void ipa_disconnect_handler(struct gsi_data_port *d_port)
@@ -491,11 +471,13 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port)
		 */
		usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
				GSI_EP_OP_SET_CLR_BLOCK_DBL);
		usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE);
		usb_gsi_ep_op(gsi->d_port.in_ep,
				&gsi->d_port.in_request, GSI_EP_OP_DISABLE);
	}

	if (gsi->d_port.out_ep)
		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE);
		usb_gsi_ep_op(gsi->d_port.out_ep,
				&gsi->d_port.out_request, GSI_EP_OP_DISABLE);

	gsi->d_port.net_ready_trigger = false;
}
@@ -3072,7 +3054,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page)
				gsi->d_port.in_channel_handle);
		len += scnprintf(buf + len, PAGE_SIZE - len,
		"%25s %10x\n", "IN Chnl Dbl Addr: ",
				gsi->d_port.in_db_reg_phs_addr_lsb);
				gsi->d_port.in_request.db_reg_phs_addr_lsb);
		len += scnprintf(buf + len, PAGE_SIZE - len,
		"%25s %10u\n", "IN TRB Ring Len: ",
				ipa_chnl_params->xfer_ring_len);
@@ -3106,7 +3088,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page)
			gsi->d_port.out_channel_handle);
		len += scnprintf(buf + len, PAGE_SIZE - len,
		"%25s %10x\n", "OUT Channel Dbl Addr: ",
			gsi->d_port.out_db_reg_phs_addr_lsb);
			gsi->d_port.out_request.db_reg_phs_addr_lsb);
		len += scnprintf(buf + len, PAGE_SIZE - len,
		"%25s %10u\n", "OUT TRB Ring Len: ",
			ipa_chnl_params->xfer_ring_len);
+1 −5
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2018, 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
@@ -232,10 +232,6 @@ struct gsi_data_port {
	struct ipa_usb_teth_params ipa_init_params;
	int in_channel_handle;
	int out_channel_handle;
	u32 in_db_reg_phs_addr_lsb;
	u32 in_db_reg_phs_addr_msb;
	u32 out_db_reg_phs_addr_lsb;
	u32 out_db_reg_phs_addr_msb;
	u32 in_xfer_rsc_index;
	u32 out_xfer_rsc_index;
	u16 in_last_trb_addr;
+6 −0
Original line number Diff line number Diff line
@@ -81,12 +81,18 @@ enum gsi_ep_op {
 * @buf_len: Size of each individual buffer is determined based on aggregation
 *	negotiated as per the protocol. In case of no aggregation supported by
 *	the protocol, we use default values.
 * @db_reg_phs_addr_lsb: IPA channel doorbell register's physical address LSB
 * @mapped_db_reg_phs_addr_lsb: doorbell LSB IOVA address mapped with IOMMU
 * @db_reg_phs_addr_msb: IPA channel doorbell register's physical address MSB
 */
struct usb_gsi_request {
	void *buf_base_addr;
	dma_addr_t dma;
	size_t num_bufs;
	size_t buf_len;
	u32 db_reg_phs_addr_lsb;
	dma_addr_t mapped_db_reg_phs_addr_lsb;
	u32 db_reg_phs_addr_msb;
};

/*