source: mainline/uspace/lib/usbhost/src/bandwidth.c@ 9bfa8c8

Last change on this file since 9bfa8c8 was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 4 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2011 Jan Vesely
3 * SPDX-FileCopyrightText: 2018 Ondrej Hlavaty
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7/** @addtogroup libusbhost
8 * @{
9 */
10/** @file
11 *
12 * Bandwidth calculation functions. Shared among uhci, ohci and ehci drivers.
13 */
14
15#include <assert.h>
16#include <stdlib.h>
17
18#include "endpoint.h"
19#include "bus.h"
20
21#include "bandwidth.h"
22
23/** Bytes per second in FULL SPEED */
24#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
25/** 90% of total bandwidth is available for periodic transfers */
26#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 * 9) / 10)
27
28/**
29 * Calculate bandwidth that needs to be reserved for communication with EP.
30 * Calculation follows USB 1.1 specification.
31 *
32 * @param ep An endpoint for which the bandwidth is to be counted
33 */
34static size_t bandwidth_count_usb11(endpoint_t *ep)
35{
36 assert(ep);
37 assert(ep->device);
38
39 const usb_transfer_type_t type = ep->transfer_type;
40
41 /* We care about bandwidth only for interrupt and isochronous. */
42 if ((type != USB_TRANSFER_INTERRUPT) &&
43 (type != USB_TRANSFER_ISOCHRONOUS)) {
44 return 0;
45 }
46
47 const size_t max_packet_size = ep->max_packet_size;
48 const size_t packet_count = ep->packets_per_uframe;
49
50 /*
51 * TODO: It may be that ISO and INT transfers use only one packet per
52 * transaction, but I did not find text in USB spec to confirm this
53 */
54 /* NOTE: All data packets will be considered to be max_packet_size */
55 switch (ep->device->speed) {
56 case USB_SPEED_LOW:
57 assert(type == USB_TRANSFER_INTERRUPT);
58 /*
59 * Protocol overhead 13B
60 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
61 * CRC bytes, and a 3-byte interpacket delay)
62 * see USB spec page 45-46.
63 */
64 /* Speed penalty 8: low speed is 8-times slower */
65 return packet_count * (13 + max_packet_size) * 8;
66 case USB_SPEED_FULL:
67 /*
68 * Interrupt transfer overhead see above
69 * or page 45 of USB spec
70 */
71 if (type == USB_TRANSFER_INTERRUPT)
72 return packet_count * (13 + max_packet_size);
73
74 assert(type == USB_TRANSFER_ISOCHRONOUS);
75 /*
76 * Protocol overhead 9B
77 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
78 * bytes, and a 1-byte interpacket delay)
79 * see USB spec page 42
80 */
81 return packet_count * (9 + max_packet_size);
82 default:
83 return 0;
84 }
85}
86
87const bandwidth_accounting_t bandwidth_accounting_usb11 = {
88 .available_bandwidth = BANDWIDTH_AVAILABLE_USB11,
89 .count_bw = &bandwidth_count_usb11,
90};
91
92/** Number of nanoseconds in one microframe */
93#define BANDWIDTH_TOTAL_USB2 (125000)
94/** 90% of total bandwidth is available for periodic transfers */
95#define BANDWIDTH_AVAILABLE_USB2 ((BANDWIDTH_TOTAL_USB2 * 9) / 10)
96
97/**
98 * Calculate bandwidth that needs to be reserved for communication with EP.
99 * Calculation follows USB 2.0 specification, chapter 5.11.3.
100 *
101 * FIXME: Interrupt transfers shall be probably divided by their polling interval.
102 *
103 * @param ep An endpoint for which the bandwidth is to be counted
104 * @return Number of nanoseconds transaction with @c size bytes payload will
105 * take.
106 */
107static size_t bandwidth_count_usb2(endpoint_t *ep)
108{
109 assert(ep);
110 assert(ep->device);
111
112 const usb_transfer_type_t type = ep->transfer_type;
113
114 /* We care about bandwidth only for interrupt and isochronous. */
115 if ((type != USB_TRANSFER_INTERRUPT) &&
116 (type != USB_TRANSFER_ISOCHRONOUS)) {
117 return 0;
118 }
119
120 // FIXME: Come up with some upper bound for these (in ns).
121 const size_t host_delay = 0;
122 const size_t hub_ls_setup = 0;
123
124 // Approx. Floor(3.167 + BitStuffTime(Data_bc))
125 const size_t base_time = (ep->max_transfer_size * 8 + 19) / 6;
126
127 switch (ep->device->speed) {
128 case USB_SPEED_LOW:
129 if (ep->direction == USB_DIRECTION_IN)
130 return 64060 + (2 * hub_ls_setup) +
131 (677 * base_time) + host_delay;
132 else
133 return 64107 + (2 * hub_ls_setup) +
134 (667 * base_time) + host_delay;
135
136 case USB_SPEED_FULL:
137 if (ep->transfer_type == USB_TRANSFER_INTERRUPT)
138 return 9107 + 84 * base_time + host_delay;
139
140 if (ep->direction == USB_DIRECTION_IN)
141 return 7268 + 84 * base_time + host_delay;
142 else
143 return 6265 + 84 * base_time + host_delay;
144
145 case USB_SPEED_HIGH:
146 if (ep->transfer_type == USB_TRANSFER_INTERRUPT)
147 return (3648 + 25 * base_time + 11) / 12 + host_delay;
148 else
149 return (5280 + 25 * base_time + 11) / 12 + host_delay;
150
151 default:
152 return 0;
153 }
154}
155
156const bandwidth_accounting_t bandwidth_accounting_usb2 = {
157 .available_bandwidth = BANDWIDTH_AVAILABLE_USB2,
158 .count_bw = &bandwidth_count_usb2,
159};
Note: See TracBrowser for help on using the repository browser.