xhci: translate virtual addresses into the bus's address space 51/267751/3
authorNicolas Saenz Julienne <nsaenzjulienne@suse.de>
Tue, 12 Jan 2021 12:55:28 +0000 (13:55 +0100)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Mon, 13 Dec 2021 02:04:10 +0000 (11:04 +0900)
So far we've been content with passing physical addresses when
configuring memory addresses into XHCI controllers, but not all
platforms have buses with transparent mappings. Specifically the
Raspberry Pi 4 might introduce an offset to memory accesses incoming
from its PCIe port.

Introduce xhci_virt_to_bus() and xhci_bus_to_virt() to cater with these
limitations, and make sure we don't break non DM users.

Change-Id: Ifde02ea1633e2fb741793b95102a9ce866028921
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Stefan Roese <sr@denx.de>
Tested-by: Peter Robinson <pbrobinson@gmail.com>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
include/usb/xhci.h

index 4c303ae..39a5574 100644 (file)
@@ -110,7 +110,7 @@ static void xhci_scratchpad_free(struct xhci_ctrl *ctrl)
 
        ctrl->dcbaa->dev_context_ptrs[0] = 0;
 
-       free((void *)(uintptr_t)le64_to_cpu(ctrl->scratchpad->sp_array[0]));
+       free(xhci_bus_to_virt(ctrl, le64_to_cpu(ctrl->scratchpad->sp_array[0])));
        free(ctrl->scratchpad->sp_array);
        free(ctrl->scratchpad);
        ctrl->scratchpad = NULL;
@@ -216,8 +216,8 @@ static void *xhci_malloc(unsigned int size)
  * @param link_trbs    flag to indicate whether to link the trbs or NOT
  * @return none
  */
-static void xhci_link_segments(struct xhci_segment *prev,
-                               struct xhci_segment *next, bool link_trbs)
+static void xhci_link_segments(struct xhci_ctrl *ctrl, struct xhci_segment *prev,
+                              struct xhci_segment *next, bool link_trbs)
 {
        u32 val;
        u64 val_64 = 0;
@@ -226,7 +226,7 @@ static void xhci_link_segments(struct xhci_segment *prev,
                return;
        prev->next = next;
        if (link_trbs) {
-               val_64 = virt_to_phys(next->trbs);
+               val_64 = xhci_virt_to_bus(ctrl, next->trbs);
                prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
                        cpu_to_le64(val_64);
 
@@ -305,7 +305,8 @@ static struct xhci_segment *xhci_segment_alloc(void)
  * @param link_trbs    flag to indicate whether to link the trbs or NOT
  * @return pointer to the newly created RING
  */
-struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
+struct xhci_ring *xhci_ring_alloc(struct xhci_ctrl *ctrl, unsigned int num_segs,
+                                 bool link_trbs)
 {
        struct xhci_ring *ring;
        struct xhci_segment *prev;
@@ -328,12 +329,12 @@ struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
                next = xhci_segment_alloc();
                BUG_ON(!next);
 
-               xhci_link_segments(prev, next, link_trbs);
+               xhci_link_segments(ctrl, prev, next, link_trbs);
 
                prev = next;
                num_segs--;
        }
-       xhci_link_segments(prev, ring->first_seg, link_trbs);
+       xhci_link_segments(ctrl, prev, ring->first_seg, link_trbs);
        if (link_trbs) {
                /* See section 4.9.2.1 and 6.4.4.1 */
                prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
@@ -355,6 +356,7 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
        struct xhci_hccr *hccr = ctrl->hccr;
        struct xhci_hcor *hcor = ctrl->hcor;
        struct xhci_scratchpad *scratchpad;
+       uint64_t val_64;
        int num_sp;
        uint32_t page_size;
        void *buf;
@@ -372,8 +374,9 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
        scratchpad->sp_array = xhci_malloc(num_sp * sizeof(u64));
        if (!scratchpad->sp_array)
                goto fail_sp2;
-       ctrl->dcbaa->dev_context_ptrs[0] =
-               cpu_to_le64((uintptr_t)scratchpad->sp_array);
+
+       val_64 = xhci_virt_to_bus(ctrl, scratchpad->sp_array);
+       ctrl->dcbaa->dev_context_ptrs[0] = cpu_to_le64(val_64);
 
        xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[0],
                sizeof(ctrl->dcbaa->dev_context_ptrs[0]));
@@ -394,8 +397,8 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
        xhci_flush_cache((uintptr_t)buf, num_sp * page_size);
 
        for (i = 0; i < num_sp; i++) {
-               uintptr_t ptr = (uintptr_t)buf + i * page_size;
-               scratchpad->sp_array[i] = cpu_to_le64(ptr);
+               val_64 = xhci_virt_to_bus(ctrl, buf + i * page_size);
+               scratchpad->sp_array[i] = cpu_to_le64(val_64);
        }
 
        xhci_flush_cache((uintptr_t)scratchpad->sp_array,
@@ -485,9 +488,9 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
        }
 
        /* Allocate endpoint 0 ring */
-       virt_dev->eps[0].ring = xhci_ring_alloc(1, true);
+       virt_dev->eps[0].ring = xhci_ring_alloc(ctrl, 1, true);
 
-       byte_64 = virt_to_phys(virt_dev->out_ctx->bytes);
+       byte_64 = xhci_virt_to_bus(ctrl, virt_dev->out_ctx->bytes);
 
        /* Point to output device context in dcbaa. */
        ctrl->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(byte_64);
@@ -523,15 +526,15 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
                return -ENOMEM;
        }
 
-       val_64 = virt_to_phys(ctrl->dcbaa);
+       val_64 = xhci_virt_to_bus(ctrl, ctrl->dcbaa);
        /* Set the pointer in DCBAA register */
        xhci_writeq(&hcor->or_dcbaap, val_64);
 
        /* Command ring control pointer register initialization */
-       ctrl->cmd_ring = xhci_ring_alloc(1, true);
+       ctrl->cmd_ring = xhci_ring_alloc(ctrl, 1, true);
 
        /* Set the address in the Command Ring Control register */
-       trb_64 = virt_to_phys(ctrl->cmd_ring->first_seg->trbs);
+       trb_64 = xhci_virt_to_bus(ctrl, ctrl->cmd_ring->first_seg->trbs);
        val_64 = xhci_readq(&hcor->or_crcr);
        val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
                (trb_64 & (u64) ~CMD_RING_RSVD_BITS) |
@@ -552,7 +555,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
        ctrl->ir_set = &ctrl->run_regs->ir_set[0];
 
        /* Event ring does not maintain link TRB */
-       ctrl->event_ring = xhci_ring_alloc(ERST_NUM_SEGS, false);
+       ctrl->event_ring = xhci_ring_alloc(ctrl, ERST_NUM_SEGS, false);
        ctrl->erst.entries = xhci_malloc(sizeof(struct xhci_erst_entry) *
                                         ERST_NUM_SEGS);
 
@@ -561,8 +564,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
        for (val = 0, seg = ctrl->event_ring->first_seg;
                        val < ERST_NUM_SEGS;
                        val++) {
-               trb_64 = virt_to_phys(seg->trbs);
                struct xhci_erst_entry *entry = &ctrl->erst.entries[val];
+               trb_64 = xhci_virt_to_bus(ctrl, seg->trbs);
                entry->seg_addr = cpu_to_le64(trb_64);
                entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
                entry->rsvd = 0;
@@ -571,7 +574,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
        xhci_flush_cache((uintptr_t)ctrl->erst.entries,
                         ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
 
-       deq = virt_to_phys(ctrl->event_ring->dequeue);
+       deq = xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue);
 
        /* Update HC event ring dequeue pointer */
        xhci_writeq(&ctrl->ir_set->erst_dequeue,
@@ -586,7 +589,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
        /* this is the event ring segment table pointer */
        val_64 = xhci_readq(&ctrl->ir_set->erst_base);
        val_64 &= ERST_PTR_MASK;
-       val_64 |= virt_to_phys(ctrl->erst.entries) & ~ERST_PTR_MASK;
+       val_64 |= xhci_virt_to_bus(ctrl, ctrl->erst.entries) & ~ERST_PTR_MASK;
 
        xhci_writeq(&ctrl->ir_set->erst_base, val_64);
 
@@ -854,7 +857,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
                        cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) |
                        ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT));
 
-       trb_64 = virt_to_phys(virt_dev->eps[0].ring->first_seg->trbs);
+       trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[0].ring->first_seg->trbs);
        ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
 
        /*
index ee7f58e..9cbce79 100644 (file)
@@ -275,10 +275,13 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
                        u32 ep_index, trb_type cmd)
 {
        u32 fields[4];
-       u64 val_64 = virt_to_phys(ptr);
+       u64 val_64 = 0;
 
        BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING));
 
+       if (ptr)
+               val_64 = xhci_virt_to_bus(ctrl, ptr);
+
        fields[0] = lower_32_bits(val_64);
        fields[1] = upper_32_bits(val_64);
        fields[2] = 0;
@@ -399,7 +402,7 @@ void xhci_acknowledge_event(struct xhci_ctrl *ctrl)
 
        /* Inform the hardware */
        xhci_writeq(&ctrl->ir_set->erst_dequeue,
-                   virt_to_phys(ctrl->event_ring->dequeue) | ERST_EHB);
+                   xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue) | ERST_EHB);
 }
 
 /**
@@ -577,7 +580,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
        u64 addr;
        int ret;
        u32 trb_fields[4];
-       u64 val_64 = virt_to_phys(buffer);
+       u64 val_64 = xhci_virt_to_bus(ctrl, buffer);
        void *last_transfer_trb_addr;
        int available_length;
 
@@ -728,7 +731,7 @@ again:
        }
 
        if ((uintptr_t)(le64_to_cpu(event->trans_event.buffer)) !=
-           (uintptr_t)virt_to_phys(last_transfer_trb_addr)) {
+           (uintptr_t)xhci_virt_to_bus(ctrl, last_transfer_trb_addr)) {
                available_length -=
                        (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len));
                xhci_acknowledge_event(ctrl);
@@ -888,7 +891,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
        if (length > 0) {
                if (req->requesttype & USB_DIR_IN)
                        field |= TRB_DIR_IN;
-               buf_64 = virt_to_phys(buffer);
+               buf_64 = xhci_virt_to_bus(ctrl, buffer);
 
                trb_fields[0] = lower_32_bits(buf_64);
                trb_fields[1] = upper_32_bits(buf_64);
index 0b95efc..76a4956 100644 (file)
@@ -606,7 +606,7 @@ static int xhci_set_configuration(struct usb_device *udev)
                ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
 
                /* Allocate the ep rings */
-               virt_dev->eps[ep_index].ring = xhci_ring_alloc(1, true);
+               virt_dev->eps[ep_index].ring = xhci_ring_alloc(ctrl, 1, true);
                if (!virt_dev->eps[ep_index].ring)
                        return -ENOMEM;
 
@@ -631,7 +631,7 @@ static int xhci_set_configuration(struct usb_device *udev)
                        cpu_to_le32(MAX_BURST(max_burst) |
                        ERROR_COUNT(err_count));
 
-               trb_64 = virt_to_phys(virt_dev->eps[ep_index].ring->enqueue);
+               trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[ep_index].ring->enqueue);
                ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |
                                virt_dev->eps[ep_index].ring->cycle_state);
 
index 75b374c..25d5bba 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef HOST_XHCI_H_
 #define HOST_XHCI_H_
 
+#include <phys2bus.h>
 #include <reset.h>
 #include <usb.h>
 #include <asm/types.h>
@@ -1230,6 +1231,12 @@ struct xhci_ctrl {
        int rootdev;
 };
 
+#if CONFIG_IS_ENABLED(DM_USB)
+#define xhci_to_dev(_ctrl)     _ctrl->dev
+#else
+#define xhci_to_dev(_ctrl)     NULL
+#endif
+
 unsigned long trb_addr(struct xhci_segment *seg, union xhci_trb *trb);
 struct xhci_input_control_ctx
                *xhci_get_input_control_ctx(struct xhci_container_ctx *ctx);
@@ -1259,7 +1266,8 @@ int xhci_check_maxpacket(struct usb_device *udev);
 void xhci_flush_cache(uintptr_t addr, u32 type_len);
 void xhci_inval_cache(uintptr_t addr, u32 type_len);
 void xhci_cleanup(struct xhci_ctrl *ctrl);
-struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs);
+struct xhci_ring *xhci_ring_alloc(struct xhci_ctrl *ctrl, unsigned int num_segs,
+                                 bool link_trbs);
 int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id);
 int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
                  struct xhci_hcor *hcor);
@@ -1289,4 +1297,14 @@ struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev);
 
 extern void xhci_pci_fixup(struct udevice *dev);
 
+static inline dma_addr_t xhci_virt_to_bus(struct xhci_ctrl *ctrl, void *addr)
+{
+       return dev_phys_to_bus(xhci_to_dev(ctrl), virt_to_phys(addr));
+}
+
+static inline void *xhci_bus_to_virt(struct xhci_ctrl *ctrl, dma_addr_t addr)
+{
+       return phys_to_virt(dev_bus_to_phys(xhci_to_dev(ctrl), addr));
+}
+
 #endif /* HOST_XHCI_H_ */