Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a1ce9bd in mainline


Ignore:
Timestamp:
2018-02-01T00:11:23Z (4 years ago)
Author:
Salmelu <salmelu@…>
Branches:
lfn, master, serial
Children:
1a2227d
Parents:
8bfb163
Message:

xhci: Split buffer into TRBs by pages

Only done for interrupt and non-stream bulk for now

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/transfers.c

    r8bfb163 ra1ce9bd  
    126126}
    127127
     128static int calculate_trb_count(xhci_transfer_t *transfer)
     129{
     130        const size_t size = transfer->batch.buffer_size;
     131        return (size + PAGE_SIZE - 1 )/ PAGE_SIZE;
     132}
     133
     134static void trb_set_buffer(xhci_transfer_t *transfer, xhci_trb_t *trb,
     135        size_t i, size_t total)
     136{
     137        const uintptr_t ptr = dma_buffer_phys(&transfer->hc_buffer,
     138                transfer->hc_buffer.virt + i * PAGE_SIZE);
     139
     140        trb->parameter = host2xhci(64, ptr);
     141        TRB_CTRL_SET_TD_SIZE(*trb, max(31, total - i - 1));
     142        if (i < total - 1) {
     143                TRB_CTRL_SET_XFER_LEN(*trb, PAGE_SIZE);
     144        }
     145        else {
     146                const size_t size = ((transfer->batch.buffer_size - 1) % PAGE_SIZE) + 1;
     147                TRB_CTRL_SET_XFER_LEN(*trb, size);
     148        }
     149}
     150
    128151static int schedule_control(xhci_hc_t* hc, xhci_transfer_t* transfer)
    129152{
     
    197220static int schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer)
    198221{
    199         xhci_trb_t trb;
    200         xhci_trb_clean(&trb);
    201         trb.parameter = host2xhci(64, transfer->hc_buffer.phys);
    202 
    203         // data size (sent for OUT, or buffer size)
    204         TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    205 
    206222        /* The stream-enabled endpoints need to chain ED trb */
    207223        xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep);
    208224        if (!ep->primary_stream_data_size) {
    209                 // FIXME: TD size 4.11.2.4
    210                 TRB_CTRL_SET_TD_SIZE(trb, 1);
    211 
    212                 // we want an interrupt after this td is done
    213                 TRB_CTRL_SET_IOC(trb, 1);
    214                 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    215 
     225                const size_t buffer_count = calculate_trb_count(transfer);
    216226                xhci_trb_ring_t* ring = get_ring(transfer);
    217                 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     227                xhci_trb_t trbs[buffer_count];
     228
     229                for (size_t i = 0; i < buffer_count; ++i) {
     230                        xhci_trb_clean(&trbs[i]);
     231                        trb_set_buffer(transfer, &trbs[i], i, buffer_count);
     232                        TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL);
     233
     234                        if (i == buffer_count - 1) break;
     235
     236                        /* Set the chain bit as this is not the last TRB */
     237                        TRB_CTRL_SET_CHAIN(trbs[i], 1);
     238                }
     239                /* Set the interrupt bit for last TRB */
     240                TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1);
     241                return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count,
     242                        &transfer->interrupt_trb_phys);
    218243        }
    219244        else {
     245                xhci_trb_t trb;
     246                xhci_trb_clean(&trb);
     247                trb.parameter = host2xhci(64, transfer->hc_buffer.phys);
     248
     249                // data size (sent for OUT, or buffer size)
     250                TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    220251                TRB_CTRL_SET_TD_SIZE(trb, 2);
    221252                TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     
    245276static int schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer)
    246277{
    247         xhci_trb_t trb;
    248         xhci_trb_clean(&trb);
    249         trb.parameter = host2xhci(64, transfer->hc_buffer.phys);
    250 
    251         // data size (sent for OUT, or buffer size)
    252         TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    253         // FIXME: TD size 4.11.2.4
    254         TRB_CTRL_SET_TD_SIZE(trb, 1);
    255 
    256         // we want an interrupt after this td is done
    257         TRB_CTRL_SET_IOC(trb, 1);
    258 
    259         TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    260 
     278        const size_t buffer_count = calculate_trb_count(transfer);
    261279        xhci_trb_ring_t* ring = get_ring(transfer);
    262 
    263         return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     280        xhci_trb_t trbs[buffer_count];
     281
     282        for (size_t i = 0; i < buffer_count; ++i) {
     283                xhci_trb_clean(&trbs[i]);
     284                trb_set_buffer(transfer, &trbs[i], i, buffer_count);
     285                TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL);
     286
     287                if (i == buffer_count - 1) break;
     288
     289                /* Set the chain bit as this is not the last TRB */
     290                TRB_CTRL_SET_CHAIN(trbs[i], 1);
     291        }
     292        /* Set the interrupt bit for last TRB */
     293        TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1);
     294        return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count,
     295                &transfer->interrupt_trb_phys);
    264296}
    265297
Note: See TracChangeset for help on using the changeset viewer.