14c67045bSKirill Smelkov /* 24c67045bSKirill Smelkov * Copyright (C) 2007 by Alan Stern 34c67045bSKirill Smelkov * 44c67045bSKirill Smelkov * This program is free software; you can redistribute it and/or modify it 54c67045bSKirill Smelkov * under the terms of the GNU General Public License as published by the 64c67045bSKirill Smelkov * Free Software Foundation; either version 2 of the License, or (at your 74c67045bSKirill Smelkov * option) any later version. 84c67045bSKirill Smelkov * 94c67045bSKirill Smelkov * This program is distributed in the hope that it will be useful, but 104c67045bSKirill Smelkov * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 114c67045bSKirill Smelkov * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 124c67045bSKirill Smelkov * for more details. 134c67045bSKirill Smelkov * 144c67045bSKirill Smelkov * You should have received a copy of the GNU General Public License 154c67045bSKirill Smelkov * along with this program; if not, write to the Free Software Foundation, 164c67045bSKirill Smelkov * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 174c67045bSKirill Smelkov */ 184c67045bSKirill Smelkov 194c67045bSKirill Smelkov /* this file is part of ehci-hcd.c */ 204c67045bSKirill Smelkov 214c67045bSKirill Smelkov 224c67045bSKirill Smelkov /* Display the ports dedicated to the companion controller */ 234c67045bSKirill Smelkov static ssize_t show_companion(struct device *dev, 244c67045bSKirill Smelkov struct device_attribute *attr, 254c67045bSKirill Smelkov char *buf) 264c67045bSKirill Smelkov { 274c67045bSKirill Smelkov struct ehci_hcd *ehci; 284c67045bSKirill Smelkov int nports, index, n; 294c67045bSKirill Smelkov int count = PAGE_SIZE; 304c67045bSKirill Smelkov char *ptr = buf; 314c67045bSKirill Smelkov 324c67045bSKirill Smelkov ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); 334c67045bSKirill Smelkov nports = HCS_N_PORTS(ehci->hcs_params); 344c67045bSKirill Smelkov 354c67045bSKirill Smelkov for (index = 0; index < nports; ++index) { 364c67045bSKirill Smelkov if (test_bit(index, &ehci->companion_ports)) { 374c67045bSKirill Smelkov n = scnprintf(ptr, count, "%d\n", index + 1); 384c67045bSKirill Smelkov ptr += n; 394c67045bSKirill Smelkov count -= n; 404c67045bSKirill Smelkov } 414c67045bSKirill Smelkov } 424c67045bSKirill Smelkov return ptr - buf; 434c67045bSKirill Smelkov } 444c67045bSKirill Smelkov 454c67045bSKirill Smelkov /* 464c67045bSKirill Smelkov * Dedicate or undedicate a port to the companion controller. 474c67045bSKirill Smelkov * Syntax is "[-]portnum", where a leading '-' sign means 484c67045bSKirill Smelkov * return control of the port to the EHCI controller. 494c67045bSKirill Smelkov */ 504c67045bSKirill Smelkov static ssize_t store_companion(struct device *dev, 514c67045bSKirill Smelkov struct device_attribute *attr, 524c67045bSKirill Smelkov const char *buf, size_t count) 534c67045bSKirill Smelkov { 544c67045bSKirill Smelkov struct ehci_hcd *ehci; 554c67045bSKirill Smelkov int portnum, new_owner; 564c67045bSKirill Smelkov 574c67045bSKirill Smelkov ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); 584c67045bSKirill Smelkov new_owner = PORT_OWNER; /* Owned by companion */ 594c67045bSKirill Smelkov if (sscanf(buf, "%d", &portnum) != 1) 604c67045bSKirill Smelkov return -EINVAL; 614c67045bSKirill Smelkov if (portnum < 0) { 624c67045bSKirill Smelkov portnum = - portnum; 634c67045bSKirill Smelkov new_owner = 0; /* Owned by EHCI */ 644c67045bSKirill Smelkov } 654c67045bSKirill Smelkov if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) 664c67045bSKirill Smelkov return -ENOENT; 674c67045bSKirill Smelkov portnum--; 684c67045bSKirill Smelkov if (new_owner) 694c67045bSKirill Smelkov set_bit(portnum, &ehci->companion_ports); 704c67045bSKirill Smelkov else 714c67045bSKirill Smelkov clear_bit(portnum, &ehci->companion_ports); 724c67045bSKirill Smelkov set_owner(ehci, portnum, new_owner); 734c67045bSKirill Smelkov return count; 744c67045bSKirill Smelkov } 754c67045bSKirill Smelkov static DEVICE_ATTR(companion, 0644, show_companion, store_companion); 764c67045bSKirill Smelkov 77cc62a7ebSKirill Smelkov 78cc62a7ebSKirill Smelkov /* 79cc62a7ebSKirill Smelkov * Display / Set uframe_periodic_max 80cc62a7ebSKirill Smelkov */ 81cc62a7ebSKirill Smelkov static ssize_t show_uframe_periodic_max(struct device *dev, 82cc62a7ebSKirill Smelkov struct device_attribute *attr, 83cc62a7ebSKirill Smelkov char *buf) 84cc62a7ebSKirill Smelkov { 85cc62a7ebSKirill Smelkov struct ehci_hcd *ehci; 86cc62a7ebSKirill Smelkov int n; 87cc62a7ebSKirill Smelkov 88cc62a7ebSKirill Smelkov ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); 89cc62a7ebSKirill Smelkov n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); 90cc62a7ebSKirill Smelkov return n; 91cc62a7ebSKirill Smelkov } 92cc62a7ebSKirill Smelkov 93cc62a7ebSKirill Smelkov 94cc62a7ebSKirill Smelkov static ssize_t store_uframe_periodic_max(struct device *dev, 95cc62a7ebSKirill Smelkov struct device_attribute *attr, 96cc62a7ebSKirill Smelkov const char *buf, size_t count) 97cc62a7ebSKirill Smelkov { 98cc62a7ebSKirill Smelkov struct ehci_hcd *ehci; 99cc62a7ebSKirill Smelkov unsigned uframe_periodic_max; 100*d0ce5c6bSAlan Stern unsigned uframe; 101cc62a7ebSKirill Smelkov unsigned long flags; 102cc62a7ebSKirill Smelkov ssize_t ret; 103cc62a7ebSKirill Smelkov 104cc62a7ebSKirill Smelkov ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); 105cc62a7ebSKirill Smelkov if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) 106cc62a7ebSKirill Smelkov return -EINVAL; 107cc62a7ebSKirill Smelkov 108cc62a7ebSKirill Smelkov if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { 109cc62a7ebSKirill Smelkov ehci_info(ehci, "rejecting invalid request for " 110cc62a7ebSKirill Smelkov "uframe_periodic_max=%u\n", uframe_periodic_max); 111cc62a7ebSKirill Smelkov return -EINVAL; 112cc62a7ebSKirill Smelkov } 113cc62a7ebSKirill Smelkov 114cc62a7ebSKirill Smelkov ret = -EINVAL; 115cc62a7ebSKirill Smelkov 116cc62a7ebSKirill Smelkov /* 117cc62a7ebSKirill Smelkov * lock, so that our checking does not race with possible periodic 118cc62a7ebSKirill Smelkov * bandwidth allocation through submitting new urbs. 119cc62a7ebSKirill Smelkov */ 120cc62a7ebSKirill Smelkov spin_lock_irqsave (&ehci->lock, flags); 121cc62a7ebSKirill Smelkov 122cc62a7ebSKirill Smelkov /* 123cc62a7ebSKirill Smelkov * for request to decrease max periodic bandwidth, we have to check 124*d0ce5c6bSAlan Stern * to see whether the decrease is possible. 125cc62a7ebSKirill Smelkov */ 126cc62a7ebSKirill Smelkov if (uframe_periodic_max < ehci->uframe_periodic_max) { 127*d0ce5c6bSAlan Stern u8 allocated_max = 0; 128cc62a7ebSKirill Smelkov 129*d0ce5c6bSAlan Stern for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe) 130cc62a7ebSKirill Smelkov allocated_max = max(allocated_max, 131*d0ce5c6bSAlan Stern ehci->bandwidth[uframe]); 132cc62a7ebSKirill Smelkov 133cc62a7ebSKirill Smelkov if (allocated_max > uframe_periodic_max) { 134cc62a7ebSKirill Smelkov ehci_info(ehci, 135cc62a7ebSKirill Smelkov "cannot decrease uframe_periodic_max becase " 136cc62a7ebSKirill Smelkov "periodic bandwidth is already allocated " 137cc62a7ebSKirill Smelkov "(%u > %u)\n", 138cc62a7ebSKirill Smelkov allocated_max, uframe_periodic_max); 139cc62a7ebSKirill Smelkov goto out_unlock; 140cc62a7ebSKirill Smelkov } 141cc62a7ebSKirill Smelkov } 142cc62a7ebSKirill Smelkov 143cc62a7ebSKirill Smelkov /* increasing is always ok */ 144cc62a7ebSKirill Smelkov 145cc62a7ebSKirill Smelkov ehci_info(ehci, "setting max periodic bandwidth to %u%% " 146cc62a7ebSKirill Smelkov "(== %u usec/uframe)\n", 147cc62a7ebSKirill Smelkov 100*uframe_periodic_max/125, uframe_periodic_max); 148cc62a7ebSKirill Smelkov 149cc62a7ebSKirill Smelkov if (uframe_periodic_max != 100) 150cc62a7ebSKirill Smelkov ehci_warn(ehci, "max periodic bandwidth set is non-standard\n"); 151cc62a7ebSKirill Smelkov 152cc62a7ebSKirill Smelkov ehci->uframe_periodic_max = uframe_periodic_max; 153cc62a7ebSKirill Smelkov ret = count; 154cc62a7ebSKirill Smelkov 155cc62a7ebSKirill Smelkov out_unlock: 156cc62a7ebSKirill Smelkov spin_unlock_irqrestore (&ehci->lock, flags); 157cc62a7ebSKirill Smelkov return ret; 158cc62a7ebSKirill Smelkov } 159cc62a7ebSKirill Smelkov static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); 160cc62a7ebSKirill Smelkov 161cc62a7ebSKirill Smelkov 1624c67045bSKirill Smelkov static inline int create_sysfs_files(struct ehci_hcd *ehci) 1634c67045bSKirill Smelkov { 164cc62a7ebSKirill Smelkov struct device *controller = ehci_to_hcd(ehci)->self.controller; 1654c67045bSKirill Smelkov int i = 0; 1664c67045bSKirill Smelkov 1674c67045bSKirill Smelkov /* with integrated TT there is no companion! */ 1684c67045bSKirill Smelkov if (!ehci_is_TDI(ehci)) 169cc62a7ebSKirill Smelkov i = device_create_file(controller, &dev_attr_companion); 170cc62a7ebSKirill Smelkov if (i) 171cc62a7ebSKirill Smelkov goto out; 172cc62a7ebSKirill Smelkov 173cc62a7ebSKirill Smelkov i = device_create_file(controller, &dev_attr_uframe_periodic_max); 174cc62a7ebSKirill Smelkov out: 1754c67045bSKirill Smelkov return i; 1764c67045bSKirill Smelkov } 1774c67045bSKirill Smelkov 1784c67045bSKirill Smelkov static inline void remove_sysfs_files(struct ehci_hcd *ehci) 1794c67045bSKirill Smelkov { 180cc62a7ebSKirill Smelkov struct device *controller = ehci_to_hcd(ehci)->self.controller; 181cc62a7ebSKirill Smelkov 1824c67045bSKirill Smelkov /* with integrated TT there is no companion! */ 1834c67045bSKirill Smelkov if (!ehci_is_TDI(ehci)) 184cc62a7ebSKirill Smelkov device_remove_file(controller, &dev_attr_companion); 185cc62a7ebSKirill Smelkov 186cc62a7ebSKirill Smelkov device_remove_file(controller, &dev_attr_uframe_periodic_max); 1874c67045bSKirill Smelkov } 188