Merge changes I1707970c,Iddb0921b into udc-qpr-dev

* changes:
  Usb: shutdown old displayport poll thread when multiple start up
  Usb: Check for displayport when booting
This commit is contained in:
Badhri Jagan Sridharan 2023-06-20 19:37:42 +00:00 committed by Android (Google) Code Review
commit 3d0153662a
2 changed files with 145 additions and 40 deletions

View file

@ -452,6 +452,9 @@ Usb::Usb()
ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2, ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2,
ThrottlingSeverity::NONE)}, kSamplingIntervalSec), ThrottlingSeverity::NONE)}, kSamplingIntervalSec),
mUsbDataEnabled(true), mUsbDataEnabled(true),
mDisplayPortPollRunning(false),
mDisplayPortPollStarting(false),
mDisplayPortCVLock(PTHREAD_MUTEX_INITIALIZER),
mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER) { mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER) {
pthread_condattr_t attr; pthread_condattr_t attr;
if (pthread_condattr_init(&attr)) { if (pthread_condattr_init(&attr)) {
@ -466,6 +469,10 @@ Usb::Usb()
ALOGE("pthread_cond_init failed: %s", strerror(errno)); ALOGE("pthread_cond_init failed: %s", strerror(errno));
abort(); abort();
} }
if (pthread_cond_init(&mDisplayPortCV, &attr)) {
ALOGE("usbdp: pthread_cond_init failed: %s", strerror(errno));
abort();
}
if (pthread_condattr_destroy(&attr)) { if (pthread_condattr_destroy(&attr)) {
ALOGE("pthread_condattr_destroy failed: %s", strerror(errno)); ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
abort(); abort();
@ -817,11 +824,22 @@ done:
void queryVersionHelper(android::hardware::usb::Usb *usb, void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus) { std::vector<PortStatus> *currentPortStatus) {
Status status; Status status;
string displayPortUsbPath;
pthread_mutex_lock(&usb->mLock); pthread_mutex_lock(&usb->mLock);
status = getPortStatusHelper(usb, currentPortStatus); status = getPortStatusHelper(usb, currentPortStatus);
queryMoistureDetectionStatus(currentPortStatus); queryMoistureDetectionStatus(currentPortStatus);
queryPowerTransferStatus(currentPortStatus); queryPowerTransferStatus(currentPortStatus);
queryNonCompliantChargerStatus(currentPortStatus); queryNonCompliantChargerStatus(currentPortStatus);
pthread_mutex_lock(&usb->mDisplayPortLock);
if (!usb->mDisplayPortFirstSetupDone &&
usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) {
ALOGI("usbdp: boot with display connected or usb hal restarted");
usb->setupDisplayPortPoll();
}
pthread_mutex_unlock(&usb->mDisplayPortLock);
if (usb->mCallback != NULL) { if (usb->mCallback != NULL) {
ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus, ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
status); status);
@ -994,7 +1012,7 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
pthread_mutex_unlock(&payload->usb->mDisplayPortLock); pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
} else if (uevent_type == UeventType::CHANGE) { } else if (uevent_type == UeventType::CHANGE) {
pthread_mutex_lock(&payload->usb->mDisplayPortLock); pthread_mutex_lock(&payload->usb->mDisplayPortLock);
payload->usb->shutdownDisplayPortPoll(); payload->usb->shutdownDisplayPortPoll(false);
pthread_mutex_unlock(&payload->usb->mDisplayPortLock); pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
} }
break; break;
@ -1184,7 +1202,7 @@ Status Usb::writeDisplayPortAttribute(string attribute, string usb_path) {
uint32_t temp; uint32_t temp;
if (!::android::base::ParseUint(Trim(attrUsb), &temp)) { if (!::android::base::ParseUint(Trim(attrUsb), &temp)) {
ALOGE("usbdp: failed parsing irq_hpd_count:%s", attrUsb.c_str()); ALOGE("usbdp: failed parsing irq_hpd_count:%s", attrUsb.c_str());
return Status::SUCCESS; return Status::ERROR;
} }
// Used to cache the values read from tcpci's irq_hpd_count. // Used to cache the values read from tcpci's irq_hpd_count.
// Update drm driver when cached value is not the same as the read value. // Update drm driver when cached value is not the same as the read value.
@ -1203,7 +1221,7 @@ Status Usb::writeDisplayPortAttribute(string attribute, string usb_path) {
} else { } else {
// Don't write anything // Don't write anything
ALOGI("usbdp: Pin config not yet chosen, nothing written."); ALOGI("usbdp: Pin config not yet chosen, nothing written.");
return Status::SUCCESS; return Status::ERROR;
} }
} }
@ -1232,7 +1250,7 @@ bool Usb::determineDisplayPortRetry(string linkPath, string hpdPath) {
static int displayPortPollOpenFileHelper(const char *file, int flags) { static int displayPortPollOpenFileHelper(const char *file, int flags) {
int fd = open(file, flags); int fd = open(file, flags);
if (fd == -1) { if (fd == -1) {
ALOGE("usbdp: open at %s failed; errno=%d", file, errno); ALOGE("usbdp: worker: open at %s failed; errno=%d", file, errno);
} }
return fd; return fd;
} }
@ -1250,14 +1268,15 @@ void *displayPortPollWork(void *param) {
string tcpcI2cBus, linkPath; string tcpcI2cBus, linkPath;
::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param; ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
usb->mDisplayPortPollRunning = true;
usb->mDisplayPortPollStarting = false;
if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) { if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) {
ALOGE("usbdp: could not locate usb displayport directory"); ALOGE("usbdp: worker: could not locate usb displayport directory");
goto usb_path_error; goto usb_path_error;
} }
usb->mDisplayPortPollRunning = true; ALOGI("usbdp: worker: displayport usb path located at %s", displayPortUsbPath.c_str());
ALOGI("usbdp: displayport usb path located at %s", displayPortUsbPath.c_str());
hpdPath = displayPortUsbPath + "hpd"; hpdPath = displayPortUsbPath + "hpd";
pinAssignmentPath = displayPortUsbPath + "pin_assignment"; pinAssignmentPath = displayPortUsbPath + "pin_assignment";
orientationPath = "/sys/class/typec/port0/orientation"; orientationPath = "/sys/class/typec/port0/orientation";
@ -1265,11 +1284,11 @@ void *displayPortPollWork(void *param) {
getI2cBusHelper(&tcpcI2cBus); getI2cBusHelper(&tcpcI2cBus);
irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath; irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath;
ALOGI("udbdp: irqHpdCountPath:%s", irqHpdCountPath.c_str()); ALOGI("usbdp: worker: irqHpdCountPath:%s", irqHpdCountPath.c_str());
epoll_fd = epoll_create(64); epoll_fd = epoll_create(64);
if (epoll_fd == -1) { if (epoll_fd == -1) {
ALOGE("usbdp: epoll_create failed; errno=%d", errno); ALOGE("usbdp: worker: epoll_create failed; errno=%d", errno);
goto epoll_fd_error; goto epoll_fd_error;
} }
@ -1301,23 +1320,23 @@ void *displayPortPollWork(void *param) {
ev_link.data.fd = link_fd; ev_link.data.fd = link_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) {
ALOGE("usbdp: epoll_ctl failed to add hpd; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add hpd; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pin_fd, &ev_pin) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pin_fd, &ev_pin) == -1) {
ALOGE("usbdp: epoll_ctl failed to add pin; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add pin; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, orientation_fd, &ev_orientation) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, orientation_fd, &ev_orientation) == -1) {
ALOGE("usbdp: epoll_ctl failed to add orientation; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_fd, &ev_link) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_fd, &ev_link) == -1) {
ALOGE("usbdp: epoll_ctl failed to add link status; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add link status; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) {
ALOGE("usbdp: epoll_ctl failed to add orientation; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
goto error; goto error;
} }
@ -1328,36 +1347,50 @@ void *displayPortPollWork(void *param) {
if (nevents == -1) { if (nevents == -1) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
ALOGE("usbdp: epoll_wait failed; errno=%d", errno); ALOGE("usbdp: worker: epoll_wait failed; errno=%d", errno);
break; break;
} }
for (int n = 0; n < nevents; n++) { for (int n = 0; n < nevents; n++) {
if (events[n].data.fd == hpd_fd) { if (events[n].data.fd == hpd_fd) {
if (!pinSet || !orientationSet) { if (!pinSet || !orientationSet) {
ALOGW("usbdp: HPD may be set before pin_assignment and orientation"); ALOGW("usbdp: worker: HPD may be set before pin_assignment and orientation");
if (!pinSet &&
usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
Status::SUCCESS) {
pinSet = true;
}
if (!orientationSet &&
usb->writeDisplayPortAttribute("orientation", orientationPath) ==
Status::SUCCESS) {
orientationSet = true;
}
} }
usb->writeDisplayPortAttribute("hpd", hpdPath); usb->writeDisplayPortAttribute("hpd", hpdPath);
} else if (events[n].data.fd == pin_fd) { } else if (events[n].data.fd == pin_fd) {
usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath); if (usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
pinSet = true; Status::SUCCESS) {
pinSet = true;
}
} else if (events[n].data.fd == orientation_fd) { } else if (events[n].data.fd == orientation_fd) {
usb->writeDisplayPortAttribute("orientation", orientationPath); if (usb->writeDisplayPortAttribute("orientation", orientationPath) ==
orientationSet = true; Status::SUCCESS) {
orientationSet = true;
}
} else if (events[n].data.fd == usb->mDisplayPortEventPipe) { } else if (events[n].data.fd == usb->mDisplayPortEventPipe) {
uint64_t flag = 0; uint64_t flag = 0;
if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) { if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) {
if (errno == EAGAIN) if (errno == EAGAIN)
continue; continue;
ALOGI("usbdp: Shutdown eventfd read error"); ALOGI("usbdp: worker: Shutdown eventfd read error");
goto error; goto error;
} }
if (flag == DISPLAYPORT_SHUTDOWN_SET) { if (flag == DISPLAYPORT_SHUTDOWN_SET) {
ALOGI("usbdp: Shutdown eventfd triggered"); ALOGI("usbdp: worker: Shutdown eventfd triggered");
destroyDisplayPortThread = true; destroyDisplayPortThread = true;
break; break;
} else if (flag == DISPLAYPORT_IRQ_HPD_COUNT_CHECK) { } else if (flag == DISPLAYPORT_IRQ_HPD_COUNT_CHECK) {
ALOGI("usbdp: IRQ_HPD event through DISPLAYPORT_IRQ_HPD_COUNT_CHECK"); ALOGI("usbdp: worker: IRQ_HPD event through DISPLAYPORT_IRQ_HPD_COUNT_CHECK");
usb->writeDisplayPortAttribute("irq_hpd_count", irqHpdCountPath); usb->writeDisplayPortAttribute("irq_hpd_count", irqHpdCountPath);
} }
} }
@ -1378,13 +1411,61 @@ hpd_fd_error:
epoll_fd_error: epoll_fd_error:
usb_path_error: usb_path_error:
usb->mDisplayPortPollRunning = false; usb->mDisplayPortPollRunning = false;
ALOGI("usbdp: Exiting worker thread"); ALOGI("usbdp: worker: exiting worker thread");
return NULL; return NULL;
} }
static struct timespec setTimespecTimer(int debounceMs) {
struct timespec to;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
to.tv_nsec = now.tv_nsec + ((debounceMs % 1000) * 1000000);
to.tv_sec = now.tv_sec + (debounceMs / 1000);
if (to.tv_nsec >= 1000000000) {
to.tv_nsec -= 1000000000;
to.tv_sec += 1;
}
return to;
}
void Usb::setupDisplayPortPoll() { void Usb::setupDisplayPortPoll() {
uint64_t flag = DISPLAYPORT_SHUTDOWN_CLEAR; uint64_t flag = DISPLAYPORT_SHUTDOWN_CLEAR;
mDisplayPortFirstSetupDone = true;
int ret;
ALOGI("usbdp: setup: beginning setup for displayport poll thread");
/*
* If thread is currently starting, then it hasn't setup DisplayPort fd's, and we can abandon
* this process.
*/
if (mDisplayPortPollStarting) {
ALOGI("usbdp: setup: abandoning poll thread because another startup is in progress");
return;
}
/*
* Check to see if thread is currently running. If it is, then we assume that it must have
* invalid DisplayPort fd's and the new thread takes over.
*/
if (mDisplayPortPollRunning) {
shutdownDisplayPortPoll(true);
pthread_mutex_lock(&mDisplayPortCVLock);
struct timespec to = setTimespecTimer(DISPLAYPORT_POLL_WAIT_MS);
ret = pthread_cond_timedwait(&mDisplayPortCV, &mDisplayPortCVLock, &to);
if (ret == ETIMEDOUT) {
ALOGI("usbdp: setup: Wait for poll to shutdown timed out, starting new poll anyways.");
}
pthread_mutex_unlock(&mDisplayPortCVLock);
}
// Indicate that startup procedure is initiated (mutex protects two threads running setup at
// once)
mDisplayPortPollStarting = true;
// Reset shutdown signals because shutdown() does not perform self clean-up
write(mDisplayPortEventPipe, &flag, sizeof(flag)); write(mDisplayPortEventPipe, &flag, sizeof(flag));
destroyDisplayPortThread = false; destroyDisplayPortThread = false;
@ -1392,42 +1473,60 @@ void Usb::setupDisplayPortPoll() {
* Create a background thread to poll DisplayPort system files * Create a background thread to poll DisplayPort system files
*/ */
if (pthread_create(&mDisplayPortPoll, NULL, displayPortPollWork, this)) { if (pthread_create(&mDisplayPortPoll, NULL, displayPortPollWork, this)) {
ALOGE("usbdp: failed to create displayport poll thread %d", errno); ALOGE("usbdp: setup: failed to create displayport poll thread %d", errno);
goto error;
} }
ALOGI("usbdp: successfully started DisplayPort poll thread"); ALOGI("usbdp: setup: successfully started displayport poll thread");
return;
error:
mDisplayPortPollStarting = false;
return; return;
} }
void Usb::shutdownDisplayPortPollHelper() { void Usb::shutdownDisplayPortPollHelper() {
uint64_t flag = DISPLAYPORT_SHUTDOWN_SET;
// Write shutdown signal to child thread.
write(mDisplayPortEventPipe, &flag, sizeof(flag));
pthread_join(mDisplayPortPoll, NULL); pthread_join(mDisplayPortPoll, NULL);
writeDisplayPortAttributeOverride("hpd", "0");
pthread_mutex_lock(&mDisplayPortCVLock);
pthread_cond_signal(&mDisplayPortCV);
pthread_mutex_unlock(&mDisplayPortCVLock);
} }
void *shutdownDisplayPortPollWork(void *param) { void *shutdownDisplayPortPollWork(void *param) {
::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param; ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
usb->shutdownDisplayPortPollHelper(); usb->shutdownDisplayPortPollHelper();
ALOGI("usbdp: DisplayPort Thread Shutdown"); ALOGI("usbdp: shutdown: displayport thread shutdown complete.");
return NULL; return NULL;
} }
void Usb::shutdownDisplayPortPoll() { void Usb::shutdownDisplayPortPoll(bool force) {
uint64_t flag = DISPLAYPORT_SHUTDOWN_SET;
string displayPortUsbPath; string displayPortUsbPath;
// Determine if should shutdown thread ALOGI("usbdp: shutdown: beginning shutdown for displayport poll thread");
// getDisplayPortUsbPathHelper locates a DisplayPort directory, no need to double check
// directory. /*
if (getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) { * Determine if should shutdown thread
*
* getDisplayPortUsbPathHelper locates a DisplayPort directory, no need to double check
* directory.
*
* Force is put in place to shutdown even when displayPortUsbPath is still present.
* Happens when back to back BIND events are sent and fds are no longer current.
*/
if (!mDisplayPortPollRunning ||
(!force && getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS)) {
return; return;
} }
// Shutdown thread, make sure to rewrite hpd because file no longer exists. // Shutdown is nonblocking to let other usb operations continue
write(mDisplayPortEventPipe, &flag, sizeof(flag));
if (pthread_create(&mDisplayPortShutdownHelper, NULL, shutdownDisplayPortPollWork, this)) { if (pthread_create(&mDisplayPortShutdownHelper, NULL, shutdownDisplayPortPollWork, this)) {
ALOGE("pthread creation failed %d", errno); ALOGE("usbdp: shutdown: shutdown worker pthread creation failed %d", errno);
} }
writeDisplayPortAttributeOverride("hpd", "0");
destroyDisplayPortThread = false;
} }
} // namespace usb } // namespace usb

View file

@ -61,6 +61,8 @@ constexpr char kGadgetName[] = "11210000.dwc3";
#define DISPLAYPORT_SHUTDOWN_SET 1 #define DISPLAYPORT_SHUTDOWN_SET 1
#define DISPLAYPORT_IRQ_HPD_COUNT_CHECK 3 #define DISPLAYPORT_IRQ_HPD_COUNT_CHECK 3
#define DISPLAYPORT_POLL_WAIT_MS 100
struct Usb : public BnUsb { struct Usb : public BnUsb {
Usb(); Usb();
@ -84,7 +86,7 @@ struct Usb : public BnUsb {
bool determineDisplayPortRetry(string linkPath, string hpdPath); bool determineDisplayPortRetry(string linkPath, string hpdPath);
void setupDisplayPortPoll(); void setupDisplayPortPoll();
void shutdownDisplayPortPollHelper(); void shutdownDisplayPortPollHelper();
void shutdownDisplayPortPoll(); void shutdownDisplayPortPoll(bool force);
std::shared_ptr<::aidl::android::hardware::usb::IUsbCallback> mCallback; std::shared_ptr<::aidl::android::hardware::usb::IUsbCallback> mCallback;
// Protects mCallback variable // Protects mCallback variable
@ -106,6 +108,10 @@ struct Usb : public BnUsb {
bool mUsbDataEnabled; bool mUsbDataEnabled;
// True when mDisplayPortPoll pthread is running // True when mDisplayPortPoll pthread is running
volatile bool mDisplayPortPollRunning; volatile bool mDisplayPortPollRunning;
volatile bool mDisplayPortPollStarting;
pthread_cond_t mDisplayPortCV;
pthread_mutex_t mDisplayPortCVLock;
volatile bool mDisplayPortFirstSetupDone;
// Used to cache the values read from tcpci's irq_hpd_count. // Used to cache the values read from tcpci's irq_hpd_count.
// Update drm driver when cached value is not the same as the read value. // Update drm driver when cached value is not the same as the read value.
uint32_t mIrqHpdCountCache; uint32_t mIrqHpdCountCache;