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