^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2007 by Alan Stern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /* this file is part of ehci-hcd.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /* Display the ports dedicated to the companion controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) static ssize_t companion_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct ehci_hcd *ehci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int nports, index, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) int count = PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) char *ptr = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) ehci = hcd_to_ehci(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) nports = HCS_N_PORTS(ehci->hcs_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) for (index = 0; index < nports; ++index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) if (test_bit(index, &ehci->companion_ports)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) n = scnprintf(ptr, count, "%d\n", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) ptr += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) count -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return ptr - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * Dedicate or undedicate a port to the companion controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Syntax is "[-]portnum", where a leading '-' sign means
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * return control of the port to the EHCI controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static ssize_t companion_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct ehci_hcd *ehci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int portnum, new_owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) ehci = hcd_to_ehci(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) new_owner = PORT_OWNER; /* Owned by companion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (sscanf(buf, "%d", &portnum) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (portnum < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) portnum = - portnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) new_owner = 0; /* Owned by EHCI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) portnum--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (new_owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) set_bit(portnum, &ehci->companion_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) clear_bit(portnum, &ehci->companion_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) set_owner(ehci, portnum, new_owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static DEVICE_ATTR_RW(companion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Display / Set uframe_periodic_max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static ssize_t uframe_periodic_max_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct ehci_hcd *ehci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ehci = hcd_to_ehci(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static ssize_t uframe_periodic_max_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct ehci_hcd *ehci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) unsigned uframe_periodic_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned uframe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) ehci = hcd_to_ehci(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ehci_info(ehci, "rejecting invalid request for "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) "uframe_periodic_max=%u\n", uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * lock, so that our checking does not race with possible periodic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * bandwidth allocation through submitting new urbs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) spin_lock_irqsave (&ehci->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * for request to decrease max periodic bandwidth, we have to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * to see whether the decrease is possible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (uframe_periodic_max < ehci->uframe_periodic_max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u8 allocated_max = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) allocated_max = max(allocated_max,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ehci->bandwidth[uframe]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (allocated_max > uframe_periodic_max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ehci_info(ehci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) "cannot decrease uframe_periodic_max because "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "periodic bandwidth is already allocated "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) "(%u > %u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) allocated_max, uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* increasing is always ok */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ehci_info(ehci, "setting max periodic bandwidth to %u%% "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) "(== %u usec/uframe)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 100*uframe_periodic_max/125, uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (uframe_periodic_max != 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ehci->uframe_periodic_max = uframe_periodic_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) spin_unlock_irqrestore (&ehci->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static DEVICE_ATTR_RW(uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static inline int create_sysfs_files(struct ehci_hcd *ehci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct device *controller = ehci_to_hcd(ehci)->self.controller;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* with integrated TT there is no companion! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!ehci_is_TDI(ehci))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) i = device_create_file(controller, &dev_attr_companion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) i = device_create_file(controller, &dev_attr_uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static inline void remove_sysfs_files(struct ehci_hcd *ehci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct device *controller = ehci_to_hcd(ehci)->self.controller;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* with integrated TT there is no companion! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (!ehci_is_TDI(ehci))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) device_remove_file(controller, &dev_attr_companion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) device_remove_file(controller, &dev_attr_uframe_periodic_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }