Changeset cb89430 in mainline for uspace/drv/bus/usb/xhci/trb_ring.c
- Timestamp:
- 2017-06-22T13:59:15Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- e4d7363
- Parents:
- 62ba2cbe
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/trb_ring.c
r62ba2cbe rcb89430 32 32 #include <as.h> 33 33 #include <align.h> 34 #include <usb/debug.h> 35 #include <usb/host/utils/malloc32.h> 36 #include "hw_struct/trb.h" 34 37 #include "trb_ring.h" 35 38 … … 42 45 43 46 struct trb_segment { 44 xhci_trb_t trb_storage [SEGMENT_TRB_COUNT] __attribute__((packed));47 xhci_trb_t trb_storage [SEGMENT_TRB_COUNT]; 45 48 46 49 link_t segments_link; … … 59 62 } 60 63 64 /** 65 * Allocate and initialize new segment. 66 * 67 * TODO: When the HC supports 64-bit addressing, there's no need to restrict 68 * to DMAMEM_4GiB. 69 */ 61 70 static int trb_segment_allocate(trb_segment_t **segment) 62 71 { … … 72 81 memset(*segment, 0, PAGE_SIZE); 73 82 (*segment)->phys = phys; 83 84 usb_log_debug2("Allocated new ring segment."); 74 85 } 75 86 … … 77 88 } 78 89 79 int trb_ring_init(xhci_trb_ring_t *ring) 90 /** 91 * Initializes the ring with one segment. 92 * Event when it fails, the structure needs to be finalized. 93 */ 94 int xhci_trb_ring_init(xhci_trb_ring_t *ring, xhci_hc_t *hc) 80 95 { 81 96 struct trb_segment *segment; 82 97 int err; 83 98 99 list_initialize(&ring->segments); 100 84 101 if ((err = trb_segment_allocate(&segment)) != EOK) 85 102 return err; 86 103 87 list_initialize(&ring->segments);88 104 list_append(&segment->segments_link, &ring->segments); 105 ring->segment_count = 1; 89 106 90 107 xhci_trb_t *last = segment_end(segment) - 1; … … 97 114 ring->pcs = 1; 98 115 99 return EOK; 100 } 101 102 int trb_ring_fini(xhci_trb_ring_t *ring) 103 { 116 usb_log_debug("Initialized new TRB ring."); 117 118 return EOK; 119 } 120 121 int xhci_trb_ring_fini(xhci_trb_ring_t *ring) 122 { 123 list_foreach(ring->segments, segments_link, trb_segment_t, segment) 124 dmamem_unmap_anonymous(segment); 104 125 return EOK; 105 126 } … … 123 144 } 124 145 125 static uintptr_t xhci_trb_ring_enqueue_phys(xhci_trb_ring_t *ring)146 static uintptr_t trb_ring_enqueue_phys(xhci_trb_ring_t *ring) 126 147 { 127 148 uintptr_t trb_id = ring->enqueue_trb - segment_begin(ring->enqueue_segment); … … 129 150 } 130 151 131 int trb_ring_enqueue(xhci_trb_ring_t *ring, xhci_trb_t *td) 152 /** 153 * Enqueue a TD composed of TRBs. 154 * 155 * This will copy all TRBs chained together into the ring. The cycle flag in 156 * TRBs may be changed. 157 * 158 * The chained TRBs must be contiguous in memory, and must not contain Link TRBs. 159 * 160 * We cannot avoid the copying, because the TRB in ring should be updated atomically. 161 * 162 * @param td the first TRB of TD 163 * @return EOK on success, 164 * EAGAIN when the ring is too full to fit all TRBs (temporary) 165 */ 166 int xhci_trb_ring_enqueue(xhci_trb_ring_t *ring, xhci_trb_t *td) 132 167 { 133 168 xhci_trb_t * const saved_enqueue_trb = ring->enqueue_trb; … … 145 180 trb_ring_resolve_link(ring); 146 181 147 if ( xhci_trb_ring_enqueue_phys(ring) == ring->dequeue)182 if (trb_ring_enqueue_phys(ring) == ring->dequeue) 148 183 goto err_again; 149 184 } while (xhci_trb_is_chained(trb++)); … … 160 195 xhci_trb_copy(ring->enqueue_trb, trb); 161 196 197 usb_log_debug2("TRB ring(%p): Enqueued TRB %p", ring, trb); 162 198 ring->enqueue_trb++; 163 199 … … 166 202 xhci_trb_set_cycle(ring->enqueue_trb, ring->pcs); 167 203 168 if (TRB_LINK_TC(*ring->enqueue_trb)) 204 if (TRB_LINK_TC(*ring->enqueue_trb)) { 169 205 ring->pcs = !ring->pcs; 206 usb_log_debug2("TRB ring(%p): PCS toggled", ring); 207 } 170 208 171 209 trb_ring_resolve_link(ring); … … 180 218 return EAGAIN; 181 219 } 220 221 /** 222 * Initializes an event ring. 223 * Even when it fails, the structure needs to be finalized. 224 */ 225 int xhci_event_ring_init(xhci_event_ring_t *ring, xhci_hc_t *hc) 226 { 227 struct trb_segment *segment; 228 int err; 229 230 list_initialize(&ring->segments); 231 232 if ((err = trb_segment_allocate(&segment)) != EOK) 233 return err; 234 235 list_append(&segment->segments_link, &ring->segments); 236 ring->segment_count = 1; 237 238 ring->dequeue_segment = segment; 239 ring->dequeue_trb = segment_begin(segment); 240 ring->dequeue_ptr = segment->phys; 241 242 ring->erst = malloc32(PAGE_SIZE); 243 if (ring->erst == NULL) 244 return ENOMEM; 245 246 xhci_fill_erst_entry(&ring->erst[0], segment->phys, SEGMENT_TRB_COUNT); 247 248 ring->ccs = 1; 249 250 usb_log_debug("Initialized event ring."); 251 252 return EOK; 253 } 254 255 int xhci_event_ring_fini(xhci_event_ring_t *ring) 256 { 257 list_foreach(ring->segments, segments_link, trb_segment_t, segment) 258 dmamem_unmap_anonymous(segment); 259 260 if (ring->erst) 261 free32(ring->erst); 262 263 return EOK; 264 } 265 266 static uintptr_t event_ring_dequeue_phys(xhci_event_ring_t *ring) 267 { 268 uintptr_t trb_id = ring->dequeue_trb - segment_begin(ring->dequeue_segment); 269 return ring->dequeue_segment->phys + trb_id * sizeof(xhci_trb_t); 270 } 271 272 /** 273 * Fill the event with next valid event from the ring. 274 * 275 * @param event pointer to event to be overwritten 276 * @return EOK on success, 277 * ENOENT when the ring is empty 278 */ 279 int xhci_event_ring_dequeue(xhci_event_ring_t *ring, xhci_trb_t *event) 280 { 281 /** 282 * The ERDP reported to the HC is a half-phase off the one we need to 283 * maintain. Therefore, we keep it extra. 284 */ 285 ring->dequeue_ptr = event_ring_dequeue_phys(ring); 286 287 if (TRB_CYCLE(*ring->dequeue_trb) != ring->ccs) 288 return ENOENT; /* The ring is empty. */ 289 290 memcpy(event, ring->dequeue_trb, sizeof(xhci_trb_t)); 291 292 ring->dequeue_trb++; 293 const unsigned index = ring->dequeue_trb - segment_begin(ring->dequeue_segment); 294 295 /* Wrapping around segment boundary */ 296 if (index >= SEGMENT_TRB_COUNT) { 297 link_t *next_segment = list_next(&ring->dequeue_segment->segments_link, &ring->segments); 298 299 /* Wrapping around table boundary */ 300 if (!next_segment) { 301 next_segment = list_first(&ring->segments); 302 ring->ccs = !ring->ccs; 303 } 304 305 ring->dequeue_segment = list_get_instance(next_segment, trb_segment_t, segments_link); 306 ring->dequeue_trb = segment_begin(ring->dequeue_segment); 307 } 308 309 310 return EOK; 311 }
Note:
See TracChangeset
for help on using the changeset viewer.