1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2007 by Alan Stern 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software Foundation, 17 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 /* this file is part of ehci-hcd.c */ 21 22 23 /* Display the ports dedicated to the companion controller */ 24 static ssize_t show_companion(struct device *dev, 25 struct device_attribute *attr, 26 char *buf) 27 { 28 struct ehci_hcd *ehci; 29 int nports, index, n; 30 int count = PAGE_SIZE; 31 char *ptr = buf; 32 33 ehci = hcd_to_ehci(dev_get_drvdata(dev)); 34 nports = HCS_N_PORTS(ehci->hcs_params); 35 36 for (index = 0; index < nports; ++index) { 37 if (test_bit(index, &ehci->companion_ports)) { 38 n = scnprintf(ptr, count, "%d\n", index + 1); 39 ptr += n; 40 count -= n; 41 } 42 } 43 return ptr - buf; 44 } 45 46 /* 47 * Dedicate or undedicate a port to the companion controller. 48 * Syntax is "[-]portnum", where a leading '-' sign means 49 * return control of the port to the EHCI controller. 50 */ 51 static ssize_t store_companion(struct device *dev, 52 struct device_attribute *attr, 53 const char *buf, size_t count) 54 { 55 struct ehci_hcd *ehci; 56 int portnum, new_owner; 57 58 ehci = hcd_to_ehci(dev_get_drvdata(dev)); 59 new_owner = PORT_OWNER; /* Owned by companion */ 60 if (sscanf(buf, "%d", &portnum) != 1) 61 return -EINVAL; 62 if (portnum < 0) { 63 portnum = - portnum; 64 new_owner = 0; /* Owned by EHCI */ 65 } 66 if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) 67 return -ENOENT; 68 portnum--; 69 if (new_owner) 70 set_bit(portnum, &ehci->companion_ports); 71 else 72 clear_bit(portnum, &ehci->companion_ports); 73 set_owner(ehci, portnum, new_owner); 74 return count; 75 } 76 static DEVICE_ATTR(companion, 0644, show_companion, store_companion); 77 78 79 /* 80 * Display / Set uframe_periodic_max 81 */ 82 static ssize_t show_uframe_periodic_max(struct device *dev, 83 struct device_attribute *attr, 84 char *buf) 85 { 86 struct ehci_hcd *ehci; 87 int n; 88 89 ehci = hcd_to_ehci(dev_get_drvdata(dev)); 90 n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); 91 return n; 92 } 93 94 95 static ssize_t store_uframe_periodic_max(struct device *dev, 96 struct device_attribute *attr, 97 const char *buf, size_t count) 98 { 99 struct ehci_hcd *ehci; 100 unsigned uframe_periodic_max; 101 unsigned uframe; 102 unsigned long flags; 103 ssize_t ret; 104 105 ehci = hcd_to_ehci(dev_get_drvdata(dev)); 106 if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) 107 return -EINVAL; 108 109 if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { 110 ehci_info(ehci, "rejecting invalid request for " 111 "uframe_periodic_max=%u\n", uframe_periodic_max); 112 return -EINVAL; 113 } 114 115 ret = -EINVAL; 116 117 /* 118 * lock, so that our checking does not race with possible periodic 119 * bandwidth allocation through submitting new urbs. 120 */ 121 spin_lock_irqsave (&ehci->lock, flags); 122 123 /* 124 * for request to decrease max periodic bandwidth, we have to check 125 * to see whether the decrease is possible. 126 */ 127 if (uframe_periodic_max < ehci->uframe_periodic_max) { 128 u8 allocated_max = 0; 129 130 for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe) 131 allocated_max = max(allocated_max, 132 ehci->bandwidth[uframe]); 133 134 if (allocated_max > uframe_periodic_max) { 135 ehci_info(ehci, 136 "cannot decrease uframe_periodic_max because " 137 "periodic bandwidth is already allocated " 138 "(%u > %u)\n", 139 allocated_max, uframe_periodic_max); 140 goto out_unlock; 141 } 142 } 143 144 /* increasing is always ok */ 145 146 ehci_info(ehci, "setting max periodic bandwidth to %u%% " 147 "(== %u usec/uframe)\n", 148 100*uframe_periodic_max/125, uframe_periodic_max); 149 150 if (uframe_periodic_max != 100) 151 ehci_warn(ehci, "max periodic bandwidth set is non-standard\n"); 152 153 ehci->uframe_periodic_max = uframe_periodic_max; 154 ret = count; 155 156 out_unlock: 157 spin_unlock_irqrestore (&ehci->lock, flags); 158 return ret; 159 } 160 static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); 161 162 163 static inline int create_sysfs_files(struct ehci_hcd *ehci) 164 { 165 struct device *controller = ehci_to_hcd(ehci)->self.controller; 166 int i = 0; 167 168 /* with integrated TT there is no companion! */ 169 if (!ehci_is_TDI(ehci)) 170 i = device_create_file(controller, &dev_attr_companion); 171 if (i) 172 goto out; 173 174 i = device_create_file(controller, &dev_attr_uframe_periodic_max); 175 out: 176 return i; 177 } 178 179 static inline void remove_sysfs_files(struct ehci_hcd *ehci) 180 { 181 struct device *controller = ehci_to_hcd(ehci)->self.controller; 182 183 /* with integrated TT there is no companion! */ 184 if (!ehci_is_TDI(ehci)) 185 device_remove_file(controller, &dev_attr_companion); 186 187 device_remove_file(controller, &dev_attr_uframe_periodic_max); 188 } 189