USB/PHY updates for 4.16-rc1

Here is the big USB and PHY driver update for 4.16-rc1.
 
 Along with the normally expected XHCI, MUSB, and Gadget driver patches,
 there are some PHY driver fixes, license cleanups, sysfs attribute
 cleanups, usbip changes, and a raft of other smaller fixes and
 additions.
 
 Full details are in the shortlog.
 
 All of these have been in the linux-next tree for a long time with no
 reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWnL0Bg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymg8gCeLg/FMtc0S/xRR/56N/sbthEebcUAnROr9Sg3
 55hDLdkyi93o9R86YOAJ
 =8d2q
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB/PHY updates from Greg KH:
 "Here is the big USB and PHY driver update for 4.16-rc1.

  Along with the normally expected XHCI, MUSB, and Gadget driver
  patches, there are some PHY driver fixes, license cleanups, sysfs
  attribute cleanups, usbip changes, and a raft of other smaller fixes
  and additions.

  Full details are in the shortlog.

  All of these have been in the linux-next tree for a long time with no
  reported issues"

* tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (137 commits)
  USB: serial: pl2303: new device id for Chilitag
  USB: misc: fix up some remaining DEVICE_ATTR() usages
  USB: musb: fix up one odd DEVICE_ATTR() usage
  USB: atm: fix up some remaining DEVICE_ATTR() usage
  USB: move many drivers to use DEVICE_ATTR_WO
  USB: move many drivers to use DEVICE_ATTR_RO
  USB: move many drivers to use DEVICE_ATTR_RW
  USB: misc: chaoskey: Use true and false for boolean values
  USB: storage: remove old wording about how to submit a change
  USB: storage: remove invalid URL from drivers
  usb: ehci-omap: don't complain on -EPROBE_DEFER when no PHY found
  usbip: list: don't list devices attached to vhci_hcd
  usbip: prevent bind loops on devices attached to vhci_hcd
  USB: serial: remove redundant initializations of 'mos_parport'
  usb/gadget: Fix "high bandwidth" check in usb_gadget_ep_match_desc()
  usb: gadget: compress return logic into one line
  usbip: vhci_hcd: update 'status' file header and format
  USB: serial: simple: add Motorola Tetra driver
  CDC-ACM: apply quirk for card reader
  usb: option: Add support for FS040U modem
  ...
This commit is contained in:
Linus Torvalds 2018-02-01 09:40:49 -08:00
commit e4ee8b85b7
160 changed files with 3874 additions and 1453 deletions

View file

@ -0,0 +1,25 @@
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc
Date: June 2017
Contact: Lu Baolu <baolu.lu@linux.intel.com>
Description:
xHCI compatible USB host controllers (i.e. super-speed
USB3 controllers) are often implemented with the Debug
Capability (DbC). It can present a debug device which
is fully compliant with the USB framework and provides
the equivalent of a very high performance full-duplex
serial link for debug purpose.
The DbC debug device shares a root port with xHCI host.
When the DbC is enabled, the root port will be assigned
to the Debug Capability. Otherwise, it will be assigned
to xHCI.
Writing "enable" to this attribute will enable the DbC
functionality and the shared root port will be assigned
to the DbC device. Writing "disable" to this attribute
will disable the DbC functionality and the shared root
port will roll back to the xHCI.
Reading this attribute gives the state of the DbC. It
can be one of the following states: disabled, enabled,
initialized, connected, configured and stalled.

View file

@ -47,6 +47,8 @@ Optional properties:
from P0 to P1/P2/P3 without delay.
- snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
during HS transmit.
- snps,dis_metastability_quirk: when set, disable metastability workaround.
CAUTION: use only if you are absolutely sure of it.
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold

View file

@ -35,10 +35,14 @@ Required properties:
- phys : a list of phandle + phy specifier pairs
Optional properties:
- mediatek,wakeup-src : 1: ip sleep wakeup mode; 2: line state wakeup
mode;
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
control register, it depends on "mediatek,wakeup-src".
- wakeup-source : enable USB remote wakeup;
- mediatek,syscon-wakeup : phandle to syscon used to access the register
of the USB wakeup glue layer between xHCI and SPM; it depends on
"wakeup-source", and has two arguments:
- the first one : register base address of the glue layer in syscon;
- the second one : hardware version of the glue layer
- 1 : used by mt8173 etc
- 2 : used by mt2712 etc
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
bit1 for u3port1, ... etc;
- vbus-supply : reference to the VBUS regulator;
@ -46,6 +50,7 @@ Optional properties:
- pinctrl-names : a pinctrl state named "default" must be defined
- pinctrl-0 : pin control group
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
- imod-interval-ns: default interrupt moderation interval is 5000ns
Example:
usb30: usb@11270000 {
@ -64,8 +69,9 @@ usb30: usb@11270000 {
vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p1_vbus>;
usb3-lpm-capable;
mediatek,syscon-wakeup = <&pericfg>;
mediatek,wakeup-src = <1>;
mediatek,syscon-wakeup = <&pericfg 0x400 1>;
wakeup-source;
imod-interval-ns = <10000>;
};
2nd: dual-role mode with xHCI driver

View file

@ -42,9 +42,14 @@ Optional properties:
- enable-manual-drd : supports manual dual-role switch via debugfs; usually
used when receptacle is TYPE-A and also wants to support dual-role
mode.
- mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
control register, it depends on "mediatek,enable-wakeup".
- wakeup-source: enable USB remote wakeup of host mode.
- mediatek,syscon-wakeup : phandle to syscon used to access the register
of the USB wakeup glue layer between SSUSB and SPM; it depends on
"wakeup-source", and has two arguments:
- the first one : register base address of the glue layer in syscon;
- the second one : hardware version of the glue layer
- 1 : used by mt8173 etc
- 2 : used by mt2712 etc
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
bit1 for u3port1, ... etc;
@ -71,8 +76,8 @@ ssusb: usb@11271000 {
vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>;
dr_mode = "otg";
mediatek,enable-wakeup;
mediatek,syscon-wakeup = <&pericfg>;
wakeup-source;
mediatek,syscon-wakeup = <&pericfg 0x400 1>;
#address-cells = <2>;
#size-cells = <2>;
ranges;

View file

@ -13,8 +13,10 @@ Required properties:
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
- "renesas,rza1-usbhs" for RZ/A1 compatible device
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first followed

View file

@ -4,8 +4,49 @@ Usually, we only use device tree for hard wired USB device.
The reference binding doc is from:
http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps
Four types of device-tree nodes are defined: "host-controller nodes"
representing USB host controllers, "device nodes" representing USB devices,
"interface nodes" representing USB interfaces and "combined nodes"
representing simple USB devices.
Required properties:
A combined node shall be used instead of a device node and an interface node
for devices of class 0 or 9 (hub) with a single configuration and a single
interface.
A "hub node" is a combined node or an interface node that represents a USB
hub.
Required properties for device nodes:
- compatible: "usbVID,PID", where VID is the vendor id and PID the product id.
The textual representation of VID and PID shall be in lower case hexadecimal
with leading zeroes suppressed. The other compatible strings from the above
standard binding could also be used, but a device adhering to this binding
may leave out all except for "usbVID,PID".
- reg: the number of the USB hub port or the USB host-controller port to which
this device is attached. The range is 1-255.
Required properties for device nodes with interface nodes:
- #address-cells: shall be 2
- #size-cells: shall be 0
Required properties for interface nodes:
- compatible: "usbifVID,PID.configCN.IN", where VID is the vendor id, PID is
the product id, CN is the configuration value and IN is the interface
number. The textual representation of VID, PID, CN and IN shall be in lower
case hexadecimal with leading zeroes suppressed. The other compatible
strings from the above standard binding could also be used, but a device
adhering to this binding may leave out all except for
"usbifVID,PID.configCN.IN".
- reg: the interface number and configuration value
The configuration component is not included in the textual representation of
an interface-node unit address for configuration 1.
Required properties for combined nodes:
- compatible: "usbVID,PID", where VID is the vendor id and PID the product id.
The textual representation of VID and PID shall be in lower case hexadecimal
with leading zeroes suppressed. The other compatible strings from the above
@ -31,8 +72,31 @@ Example:
#address-cells = <1>;
#size-cells = <0>;
hub@1 { /* hub connected to port 1 */
hub@1 { /* hub connected to port 1 */
compatible = "usb5e3,608";
reg = <1>;
};
device@2 { /* device connected to port 2 */
compatible = "usb123,4567";
reg = <2>;
};
device@3 { /* device connected to port 3 */
compatible = "usb123,abcd";
reg = <3>;
#address-cells = <2>;
#size-cells = <0>;
interface@0 { /* interface 0 of configuration 1 */
compatible = "usbif123,abcd.config1.0";
reg = <0 1>;
};
interface@0,2 { /* interface 0 of configuration 2 */
compatible = "usbif123,abcd.config2.0";
reg = <0 2>;
};
};
};

View file

@ -7,12 +7,14 @@ Required properties:
- "marvell,armada3700-xhci" for Armada 37xx SoCs
- "marvell,armada-375-xhci" for Armada 375 SoCs
- "marvell,armada-380-xhci" for Armada 38x SoCs
- "renesas,xhci-r8a7743" for r8a7743 SoC
- "renesas,xhci-r8a7790" for r8a7790 SoC
- "renesas,xhci-r8a7791" for r8a7791 SoC
- "renesas,xhci-r8a7793" for r8a7793 SoC
- "renesas,xhci-r8a7795" for r8a7795 SoC
- "renesas,xhci-r8a7796" for r8a7796 SoC
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
- "xhci-platform" (deprecated)
@ -29,6 +31,7 @@ Optional properties:
- usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
- usb3-lpm-capable: determines if platform is USB3 LPM capable
- quirk-broken-port-ped: set if the controller has broken port disable mechanism
- imod-interval-ns: default interrupt moderation interval is 5000ns
Example:
usb@f0931000 {

View file

@ -274,7 +274,6 @@ USBIP_CMD_SUBMIT: Submit an URB
URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no
URB_ISO_ASAP | 0x00000002 | no | no | no | yes
URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes
URB_NO_FSBR | 0x00000020 | yes | no | no | no
URB_ZERO_PACKET | 0x00000040 | no | no | only out | no
URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes
URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes

View file

@ -417,7 +417,7 @@ static struct clk_lookup da830_clks[] = {
CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
CLK("davinci-mcasp.1", NULL, &mcasp1_clk),
CLK("davinci-mcasp.2", NULL, &mcasp2_clk),
CLK("musb-da8xx", "usb20", &usb20_clk),
CLK("musb-da8xx", NULL, &usb20_clk),
CLK("cppi41-dmaengine", NULL, &cppi41_clk),
CLK(NULL, "aemif", &aemif_clk),
CLK(NULL, "aintc", &aintc_clk),
@ -426,7 +426,7 @@ static struct clk_lookup da830_clks[] = {
CLK("davinci_mdio.0", "fck", &emac_clk),
CLK(NULL, "gpio", &gpio_clk),
CLK("i2c_davinci.2", NULL, &i2c1_clk),
CLK("ohci-da8xx", "usb11", &usb11_clk),
CLK("ohci-da8xx", NULL, &usb11_clk),
CLK(NULL, "emif3", &emif3_clk),
CLK(NULL, "arm", &arm_clk),
CLK(NULL, "rmii", &rmii_clk),

View file

@ -563,8 +563,8 @@ static struct clk_lookup da850_clks[] = {
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
CLK("ti-aemif", NULL, &aemif_clk),
CLK("davinci-nand.0", "aemif", &aemif_nand_clk),
CLK("ohci-da8xx", "usb11", &usb11_clk),
CLK("musb-da8xx", "usb20", &usb20_clk),
CLK("ohci-da8xx", NULL, &usb11_clk),
CLK("musb-da8xx", NULL, &usb20_clk),
CLK("cppi41-dmaengine", NULL, &cppi41_clk),
CLK("spi_davinci.0", NULL, &spi0_clk),
CLK("spi_davinci.1", NULL, &spi1_clk),

View file

@ -505,7 +505,7 @@
vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>;
dr_mode = "otg";
mediatek,enable-wakeup;
wakeup-source;
pinctrl-names = "default", "id_float", "id_ground";
pinctrl-0 = <&usb_id_pins_float>;
pinctrl-1 = <&usb_id_pins_float>;

View file

@ -731,15 +731,9 @@
<&u3port0 PHY_TYPE_USB3>,
<&u2port1 PHY_TYPE_USB2>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>,
<&clk26m>,
<&pericfg CLK_PERI_USB0>,
<&pericfg CLK_PERI_USB1>;
clock-names = "sys_ck",
"ref_ck",
"wakeup_deb_p0",
"wakeup_deb_p1";
mediatek,syscon-wakeup = <&pericfg>;
clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>;
clock-names = "sys_ck", "ref_ck";
mediatek,syscon-wakeup = <&pericfg 0x400 1>;
#address-cells = <2>;
#size-cells = <2>;
ranges;

View file

@ -50,6 +50,8 @@
#define USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK 0x80000000 /* option */
#define USB_CTRL_EBRIDGE 0x0c
#define USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK 0x00020000 /* option */
#define USB_CTRL_OBRIDGE 0x10
#define USB_CTRL_OBRIDGE_LS_KEEP_ALIVE_MASK 0x08000000
#define USB_CTRL_MDIO 0x14
#define USB_CTRL_MDIO2 0x18
#define USB_CTRL_UTMI_CTL_1 0x2c
@ -71,6 +73,7 @@
#define USB_CTRL_USB30_CTL1_USB3_IPP_MASK 0x20000000 /* option */
#define USB_CTRL_USB30_PCTL 0x70
#define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_MASK 0x00000002
#define USB_CTRL_USB30_PCTL_PHY3_IDDQ_OVERRIDE_MASK 0x00008000
#define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_P1_MASK 0x00020000
#define USB_CTRL_USB_DEVICE_CTL1 0x90
#define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003 /* option */
@ -116,7 +119,6 @@ enum {
USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR,
USB_CTRL_SETUP_OC3_DISABLE_SELECTOR,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR,
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_SELECTOR,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR,
USB_CTRL_USB_PM_USB_PWRDN_SELECTOR,
@ -203,7 +205,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -225,7 +226,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK,
0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
@ -247,7 +247,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -269,7 +268,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK,
0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
@ -291,7 +289,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -313,7 +310,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */
0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
@ -335,7 +331,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -357,7 +352,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */
0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
@ -379,7 +373,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -401,7 +394,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
USB_CTRL_USB_PM_USB_PWRDN_MASK,
@ -926,6 +918,7 @@ void brcm_usb_init_common(struct brcm_usb_init_params *params)
USB_CTRL_UNSET_FAMILY(params, USB_PM, BDC_SOFT_RESETB);
break;
default:
USB_CTRL_UNSET_FAMILY(params, USB_PM, BDC_SOFT_RESETB);
USB_CTRL_SET_FAMILY(params, USB_PM, BDC_SOFT_RESETB);
break;
}
@ -952,13 +945,17 @@ void brcm_usb_init_eohci(struct brcm_usb_init_params *params)
* Don't enable this so the memory controller doesn't read
* into memory holes. NOTE: This bit is low true on 7366C0.
*/
USB_CTRL_SET_FAMILY(params, EBRIDGE, ESTOP_SCB_REQ);
USB_CTRL_SET(ctrl, EBRIDGE, ESTOP_SCB_REQ);
/* Setup the endian bits */
reg = brcmusb_readl(USB_CTRL_REG(ctrl, SETUP));
reg &= ~USB_CTRL_SETUP_ENDIAN_BITS;
reg |= USB_CTRL_MASK_FAMILY(params, SETUP, ENDIAN);
brcmusb_writel(reg, USB_CTRL_REG(ctrl, SETUP));
if (params->selected_family == BRCM_FAMILY_7271A0)
/* Enable LS keep alive fix for certain keyboards */
USB_CTRL_SET(ctrl, OBRIDGE, LS_KEEP_ALIVE);
}
void brcm_usb_init_xhci(struct brcm_usb_init_params *params)
@ -1003,6 +1000,7 @@ void brcm_usb_uninit_eohci(struct brcm_usb_init_params *params)
void brcm_usb_uninit_xhci(struct brcm_usb_init_params *params)
{
brcmusb_xhci_soft_reset(params, 1);
USB_CTRL_SET(params->ctrl_regs, USB30_PCTL, PHY3_IDDQ_OVERRIDE);
}
void brcm_usb_set_family_map(struct brcm_usb_init_params *params)

View file

@ -338,9 +338,9 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
ARRAY_SIZE(brcm_dr_mode_to_name),
mode, &priv->ini.mode);
}
if (of_property_read_bool(dn, "brcm,has_xhci"))
if (of_property_read_bool(dn, "brcm,has-xhci"))
priv->has_xhci = true;
if (of_property_read_bool(dn, "brcm,has_eohci"))
if (of_property_read_bool(dn, "brcm,has-eohci"))
priv->has_eohci = true;
err = brcm_usb_phy_dvr_init(dev, priv, dn);

View file

@ -20,6 +20,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@ -440,9 +441,9 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy,
u32 index = instance->index;
u32 tmp;
/* switch to USB function. (system register, force ip into usb mode) */
/* switch to USB function, and enable usb pll */
tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~P2C_FORCE_UART_EN;
tmp &= ~(P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM);
tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
writel(tmp, com + U3P_U2PHYDTM0);
@ -502,10 +503,8 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
u32 index = instance->index;
u32 tmp;
/* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
writel(tmp, com + U3P_U2PHYDTM0);
/* OTG Enable */
@ -540,7 +539,6 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
tmp |= P2C_FORCE_SUSPENDM;
writel(tmp, com + U3P_U2PHYDTM0);
/* OTG Disable */
@ -548,18 +546,16 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
writel(tmp, com + U3P_USBPHYACR6);
/* let suspendm=0, set utmi into analog power down */
tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~P2C_RG_SUSPENDM;
writel(tmp, com + U3P_U2PHYDTM0);
udelay(1);
tmp = readl(com + U3P_U2PHYDTM1);
tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
tmp |= P2C_RG_SESSEND;
writel(tmp, com + U3P_U2PHYDTM1);
if (tphy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~(P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM);
writel(tmp, com + U3P_U2PHYDTM0);
tmp = readl(com + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, com + U3D_U2PHYDCR0);
@ -1000,7 +996,6 @@ MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
static int mtk_tphy_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *child_np;
@ -1010,15 +1005,14 @@ static int mtk_tphy_probe(struct platform_device *pdev)
struct resource res;
int port, retval;
match = of_match_node(mtk_tphy_id_table, pdev->dev.of_node);
if (!match)
return -EINVAL;
tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL);
if (!tphy)
return -ENOMEM;
tphy->pdata = match->data;
tphy->pdata = of_device_get_match_data(dev);
if (!tphy->pdata)
return -EINVAL;
tphy->nphys = of_get_child_count(np);
tphy->phys = devm_kcalloc(dev, tphy->nphys,
sizeof(*tphy->phys), GFP_KERNEL);
@ -1028,9 +1022,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)
tphy->dev = dev;
platform_set_drvdata(pdev, tphy);
if (tphy->pdata->version == MTK_PHY_V1) {
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* SATA phy of V1 needn't it if not shared with PCIe or USB */
if (sif_res && tphy->pdata->version == MTK_PHY_V1) {
/* get banks shared by multiple phys */
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tphy->sif_base = devm_ioremap_resource(dev, sif_res);
if (IS_ERR(tphy->sif_base)) {
dev_err(dev, "failed to remap sif regs\n");

View file

@ -90,7 +90,17 @@
#define PHYCLKRST_COMMONONN BIT(0)
#define EXYNOS5_DRD_PHYREG0 0x14
#define PHYREG0_SSC_REF_CLK_SEL BIT(21)
#define PHYREG0_SSC_RANGE BIT(20)
#define PHYREG0_CR_WRITE BIT(19)
#define PHYREG0_CR_READ BIT(18)
#define PHYREG0_CR_DATA_IN(_x) ((_x) << 2)
#define PHYREG0_CR_CAP_DATA BIT(1)
#define PHYREG0_CR_CAP_ADDR BIT(0)
#define EXYNOS5_DRD_PHYREG1 0x18
#define PHYREG1_CR_DATA_OUT(_x) ((_x) << 1)
#define PHYREG1_CR_ACK BIT(0)
#define EXYNOS5_DRD_PHYPARAM0 0x1c
@ -119,6 +129,25 @@
#define EXYNOS5_DRD_PHYRESUME 0x34
#define EXYNOS5_DRD_LINKPORT 0x44
/* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */
#define EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN (0x15)
#define LOSLEVEL_OVRD_IN_LOS_BIAS_5420 (0x5 << 13)
#define LOSLEVEL_OVRD_IN_LOS_BIAS_DEFAULT (0x0 << 13)
#define LOSLEVEL_OVRD_IN_EN (0x1 << 10)
#define LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT (0x9 << 0)
#define EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN (0x12)
#define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420 (0x5 << 13)
#define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_DEFAULT (0x4 << 13)
#define EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG (0x1010)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M (0x4 << 4)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M (0x8 << 4)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_25M_26M (0x8 << 4)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M (0x20 << 4)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_62M5 (0x20 << 4)
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_96M_100M (0x40 << 4)
#define KHZ 1000
#define MHZ (KHZ * KHZ)
@ -527,6 +556,151 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
return 0;
}
static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd,
u32 val, u32 cmd)
{
u32 usec = 100;
unsigned int result;
writel(val | cmd, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
do {
result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1);
if (result & PHYREG1_CR_ACK)
break;
udelay(1);
} while (usec-- > 0);
if (!usec) {
dev_err(phy_drd->dev,
"CRPORT handshake timeout1 (0x%08x)\n", val);
return -ETIME;
}
usec = 100;
writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
do {
result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1);
if (!(result & PHYREG1_CR_ACK))
break;
udelay(1);
} while (usec-- > 0);
if (!usec) {
dev_err(phy_drd->dev,
"CRPORT handshake timeout2 (0x%08x)\n", val);
return -ETIME;
}
return 0;
}
static int crport_ctrl_write(struct exynos5_usbdrd_phy *phy_drd,
u32 addr, u32 data)
{
int ret;
/* Write Address */
writel(PHYREG0_CR_DATA_IN(addr),
phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(addr),
PHYREG0_CR_CAP_ADDR);
if (ret)
return ret;
/* Write Data */
writel(PHYREG0_CR_DATA_IN(data),
phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
PHYREG0_CR_CAP_DATA);
if (ret)
return ret;
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
PHYREG0_CR_WRITE);
return ret;
}
/*
* Calibrate few PHY parameters using CR_PORT register to meet
* SuperSpeed requirements on Exynos5420 and Exynos5800 systems,
* which have 28nm USB 3.0 DRD PHY.
*/
static int exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy *phy_drd)
{
unsigned int temp;
int ret = 0;
/*
* Change los_bias to (0x5) for 28nm PHY from a
* default value (0x0); los_level is set as default
* (0x9) as also reflected in los_level[30:26] bits
* of PHYPARAM0 register.
*/
temp = LOSLEVEL_OVRD_IN_LOS_BIAS_5420 |
LOSLEVEL_OVRD_IN_EN |
LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT;
ret = crport_ctrl_write(phy_drd,
EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN,
temp);
if (ret) {
dev_err(phy_drd->dev,
"Failed setting Loss-of-Signal level for SuperSpeed\n");
return ret;
}
/*
* Set tx_vboost_lvl to (0x5) for 28nm PHY Tuning,
* to raise Tx signal level from its default value of (0x4)
*/
temp = TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420;
ret = crport_ctrl_write(phy_drd,
EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN,
temp);
if (ret) {
dev_err(phy_drd->dev,
"Failed setting Tx-Vboost-Level for SuperSpeed\n");
return ret;
}
/*
* Set proper time to wait for RxDetect measurement, for
* desired reference clock of PHY, by tuning the CR_PORT
* register LANE0.TX_DEBUG which is internal to PHY.
* This fixes issue with few USB 3.0 devices, which are
* not detected (not even generate interrupts on the bus
* on insertion) without this change.
* e.g. Samsung SUM-TSB16S 3.0 USB drive.
*/
switch (phy_drd->extrefclk) {
case EXYNOS5_FSEL_50MHZ:
temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M;
break;
case EXYNOS5_FSEL_20MHZ:
case EXYNOS5_FSEL_19MHZ2:
temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M;
break;
case EXYNOS5_FSEL_24MHZ:
default:
temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M;
break;
}
ret = crport_ctrl_write(phy_drd,
EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG,
temp);
if (ret)
dev_err(phy_drd->dev,
"Fail to set RxDet measurement time for SuperSpeed\n");
return ret;
}
static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
struct of_phandle_args *args)
{
@ -538,11 +712,20 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
return phy_drd->phys[args->args[0]].phy;
}
static int exynos5_usbdrd_phy_calibrate(struct phy *phy)
{
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
return exynos5420_usbdrd_phy_calibrate(phy_drd);
}
static const struct phy_ops exynos5_usbdrd_phy_ops = {
.init = exynos5_usbdrd_phy_init,
.exit = exynos5_usbdrd_phy_exit,
.power_on = exynos5_usbdrd_phy_power_on,
.power_off = exynos5_usbdrd_phy_power_off,
.calibrate = exynos5_usbdrd_phy_calibrate,
.owner = THIS_MODULE,
};

View file

@ -196,18 +196,16 @@ static void cxacru_poll_status(struct work_struct *work);
/* Card info exported through sysfs */
#define CXACRU__ATTR_INIT(_name) \
static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
static DEVICE_ATTR_RO(_name)
#define CXACRU_CMD_INIT(_name) \
static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
static DEVICE_ATTR_RW(_name)
#define CXACRU_SET_INIT(_name) \
static DEVICE_ATTR(_name, S_IWUSR, \
NULL, cxacru_sysfs_store_##_name)
static DEVICE_ATTR_WO(_name)
#define CXACRU_ATTR_INIT(_value, _type, _name) \
static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
static ssize_t _name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct cxacru_data *instance = to_usbatm_driver_data(\
@ -302,7 +300,7 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
* MAC_ADDRESS_LOW = 0x33221100
* Where 00-55 are bytes 0-5 of the MAC.
*/
static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
static ssize_t mac_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cxacru_data *instance = to_usbatm_driver_data(
@ -315,7 +313,7 @@ static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
instance->usbatm->atm_dev->esi);
}
static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
static ssize_t adsl_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
static char *str[] = { "running", "stopped" };
@ -332,7 +330,7 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
static ssize_t adsl_state_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cxacru_data *instance = to_usbatm_driver_data(
@ -435,7 +433,7 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */
static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
static ssize_t adsl_config_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cxacru_data *instance = to_usbatm_driver_data(

View file

@ -2280,7 +2280,7 @@ static struct uea_softc *dev_to_uea(struct device *dev)
return usbatm->driver_data;
}
static ssize_t read_status(struct device *dev, struct device_attribute *attr,
static ssize_t stat_status_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret = -ENODEV;
@ -2296,7 +2296,7 @@ out:
return ret;
}
static ssize_t reboot(struct device *dev, struct device_attribute *attr,
static ssize_t stat_status_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = -ENODEV;
@ -2313,9 +2313,9 @@ out:
return ret;
}
static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot);
static DEVICE_ATTR_RW(stat_status);
static ssize_t read_human_status(struct device *dev,
static ssize_t stat_human_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = -ENODEV;
@ -2376,9 +2376,9 @@ out:
return ret;
}
static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL);
static DEVICE_ATTR_RO(stat_human_status);
static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
static ssize_t stat_delin_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret = -ENODEV;
@ -2408,11 +2408,11 @@ out:
return ret;
}
static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL);
static DEVICE_ATTR_RO(stat_delin);
#define UEA_ATTR(name, reset) \
\
static ssize_t read_##name(struct device *dev, \
static ssize_t stat_##name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
int ret = -ENODEV; \
@ -2430,7 +2430,7 @@ out: \
return ret; \
} \
\
static DEVICE_ATTR(stat_##name, S_IRUGO, read_##name, NULL)
static DEVICE_ATTR_RO(stat_##name)
UEA_ATTR(mflags, 1);
UEA_ATTR(vidcpe, 0);

View file

@ -29,7 +29,7 @@ static const struct tegra_udc_soc_info tegra20_udc_soc_info = {
};
static const struct tegra_udc_soc_info tegra30_udc_soc_info = {
.flags = 0,
.flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
};
static const struct tegra_udc_soc_info tegra114_udc_soc_info = {

View file

@ -835,7 +835,7 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
}
}
static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
static ssize_t role_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -846,7 +846,7 @@ static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
return 0;
}
static ssize_t ci_role_store(struct device *dev,
static ssize_t role_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -877,7 +877,7 @@ static ssize_t ci_role_store(struct device *dev,
return (ret == 0) ? n : ret;
}
static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store);
static DEVICE_ATTR_RW(role);
static struct attribute *ci_attrs[] = {
&dev_attr_role.attr,

View file

@ -29,7 +29,7 @@
/* Add for otg: interact with user space app */
static ssize_t
get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf)
{
char *next;
unsigned size, t;
@ -45,7 +45,7 @@ get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
set_a_bus_req(struct device *dev, struct device_attribute *attr,
a_bus_req_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -75,10 +75,10 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
static DEVICE_ATTR_RW(a_bus_req);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
a_bus_drop_show(struct device *dev, struct device_attribute *attr, char *buf)
{
char *next;
unsigned size, t;
@ -94,7 +94,7 @@ get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
set_a_bus_drop(struct device *dev, struct device_attribute *attr,
a_bus_drop_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -115,11 +115,10 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop,
set_a_bus_drop);
static DEVICE_ATTR_RW(a_bus_drop);
static ssize_t
get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
b_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf)
{
char *next;
unsigned size, t;
@ -135,7 +134,7 @@ get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
set_b_bus_req(struct device *dev, struct device_attribute *attr,
b_bus_req_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -160,10 +159,10 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
static DEVICE_ATTR_RW(b_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
a_clr_err_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@ -180,7 +179,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static DEVICE_ATTR_WO(a_clr_err);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,

View file

@ -235,7 +235,7 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
/*
* attributes exported through sysfs
*/
static ssize_t show_caps
static ssize_t bmCapabilities_show
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -243,9 +243,9 @@ static ssize_t show_caps
return sprintf(buf, "%d", acm->ctrl_caps);
}
static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
static DEVICE_ATTR_RO(bmCapabilities);
static ssize_t show_country_codes
static ssize_t wCountryCodes_show
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -255,9 +255,9 @@ static ssize_t show_country_codes
return acm->country_code_size;
}
static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
static DEVICE_ATTR_RO(wCountryCodes);
static ssize_t show_country_rel_date
static ssize_t iCountryCodeRelDate_show
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -266,7 +266,7 @@ static ssize_t show_country_rel_date
return sprintf(buf, "%d", acm->country_rel_date);
}
static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
static DEVICE_ATTR_RO(iCountryCodeRelDate);
/*
* Interrupt handlers for various ACM device responses
*/
@ -425,7 +425,7 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
res = usb_submit_urb(acm->read_urbs[index], mem_flags);
if (res) {
if (res != -EPERM) {
if (res != -EPERM && res != -ENODEV) {
dev_err(&acm->data->dev,
"urb %d failed submission with %d\n",
index, res);
@ -1752,6 +1752,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
{ USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
.driver_info = SINGLE_RX_URB,
},
{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},

View file

@ -1066,7 +1066,7 @@ static struct usb_class_driver usblp_class = {
.minor_base = USBLP_MINOR_BASE,
};
static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t ieee1284_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usblp *usblp = usb_get_intfdata(intf);
@ -1078,7 +1078,7 @@ static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribut
return sprintf(buf, "%s", usblp->device_id_string+2);
}
static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL);
static DEVICE_ATTR_RO(ieee1284_id);
static int usblp_probe(struct usb_interface *intf,
const struct usb_device_id *id)

View file

@ -1681,8 +1681,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
u |= URB_ISO_ASAP;
if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in)
u |= URB_SHORT_NOT_OK;
if (uurb->flags & USBDEVFS_URB_NO_FSBR)
u |= URB_NO_FSBR;
if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
u |= URB_ZERO_PACKET;
if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)

View file

@ -342,8 +342,8 @@ static int usb_probe_interface(struct device *dev)
if (driver->disable_hub_initiated_lpm) {
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error) {
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n",
__func__, driver->name);
error = lpm_disable_error;
goto err;
}
@ -537,8 +537,8 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (driver->disable_hub_initiated_lpm) {
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error) {
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n",
__func__, driver->name);
return -ENOMEM;
}
}
@ -1070,7 +1070,7 @@ static void usb_rebind_intf(struct usb_interface *intf)
if (!intf->dev.power.is_prepared) {
intf->needs_binding = 0;
rc = device_attach(&intf->dev);
if (rc < 0)
if (rc < 0 && rc != -EPROBE_DEFER)
dev_warn(&intf->dev, "rebind failed: %d\n", rc);
}
}

View file

@ -38,6 +38,9 @@
#define USB_VENDOR_GENESYS_LOGIC 0x05e3
#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
#define USB_TP_TRANSMISSION_DELAY 40 /* ns */
#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */
/* Protect struct usb_device->state and ->children members
* Note: Both are also protected by ->dev.sem, except that ->state can
* change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
@ -1049,12 +1052,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
ret = hcd->driver->update_hub_device(hcd, hdev,
&hub->tt, GFP_NOIO);
if (ret < 0) {
dev_err(hub->intfdev, "Host not "
"accepting hub info "
"update.\n");
dev_err(hub->intfdev, "LS/FS devices "
"and hubs may not work "
"under this hub\n.");
dev_err(hub->intfdev,
"Host not accepting hub info update\n");
dev_err(hub->intfdev,
"LS/FS devices and hubs may not work under this hub\n");
}
}
hub_power_on(hub, true);
@ -1352,6 +1353,20 @@ static int hub_configure(struct usb_hub *hub,
goto fail;
}
/*
* Accumulate wHubDelay + 40ns for every hub in the tree of devices.
* The resulting value will be used for SetIsochDelay() request.
*/
if (hub_is_superspeed(hdev) || hub_is_superspeedplus(hdev)) {
u32 delay = __le16_to_cpu(hub->descriptor->u.ss.wHubDelay);
if (hdev->parent)
delay += hdev->parent->hub_delay;
delay += USB_TP_TRANSMISSION_DELAY;
hdev->hub_delay = min_t(u32, delay, USB_TP_TRANSMISSION_DELAY_MAX);
}
maxchild = hub->descriptor->bNbrPorts;
dev_info(hub_dev, "%d port%s detected\n", maxchild,
(maxchild == 1) ? "" : "s");
@ -3157,7 +3172,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
usb_set_usb2_hardware_lpm(udev, 0);
if (usb_disable_ltm(udev)) {
dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
dev_err(&udev->dev, "Failed to disable LTM before suspend\n");
status = -ENOMEM;
if (PMSG_IS_AUTO(msg))
goto err_ltm;
@ -4599,7 +4614,20 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval >= 0)
retval = -EMSGSIZE;
} else {
u32 delay;
retval = 0;
delay = udev->parent->hub_delay;
udev->hub_delay = min_t(u32, delay,
USB_TP_TRANSMISSION_DELAY_MAX);
retval = usb_set_isoch_delay(udev);
if (retval) {
dev_dbg(&udev->dev,
"Failed set isoch delay, error %d\n",
retval);
retval = 0;
}
break;
}
}
@ -5484,13 +5512,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
*/
ret = usb_unlocked_disable_lpm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__);
goto re_enumerate_no_bos;
}
ret = usb_disable_ltm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LTM\n.",
__func__);
dev_err(&udev->dev, "%s Failed to disable LTM\n", __func__);
goto re_enumerate_no_bos;
}

View file

@ -137,11 +137,17 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data,
if (!led_np)
return false;
/* Get node of port being added */
port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1);
/*
* Get node of port being added
*
* FIXME: This is really the device node of the connected device
*/
port_np = usb_of_get_device_node(usb_dev, port1);
if (!port_np)
return false;
of_node_put(port_np);
/* Amount of trigger sources for this LED */
count = of_count_phandle_with_args(led_np, "trigger-sources",
"#trigger-source-cells");

View file

@ -18,6 +18,7 @@
#include <linux/usb/cdc.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h> /* for usbcore internals */
#include <linux/usb/of.h>
#include <asm/byteorder.h>
#include "usb.h"
@ -776,7 +777,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
* deal with strings at all. Set string_langid to -1 in order to
* prevent any string to be retrieved from the device */
if (err < 0) {
dev_err(&dev->dev, "string descriptor 0 read error: %d\n",
dev_info(&dev->dev, "string descriptor 0 read error: %d\n",
err);
dev->string_langid = -1;
return -EPIPE;
@ -915,6 +916,30 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
return ret;
}
/*
* usb_set_isoch_delay - informs the device of the packet transmit delay
* @dev: the device whose delay is to be informed
* Context: !in_interrupt()
*
* Since this is an optional request, we don't bother if it fails.
*/
int usb_set_isoch_delay(struct usb_device *dev)
{
/* skip hub devices */
if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
return 0;
/* skip non-SS/non-SSP devices */
if (dev->speed < USB_SPEED_SUPER)
return 0;
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_ISOCH_DELAY,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
cpu_to_le16(dev->hub_delay), 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
/**
* usb_get_status - issues a GET_STATUS call
* @dev: the device whose status is being checked
@ -1355,7 +1380,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* so that the xHCI driver can recalculate the U1/U2 timeouts.
*/
if (usb_disable_lpm(dev)) {
dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
dev_err(&iface->dev, "%s Failed to disable LPM\n", __func__);
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
@ -1499,7 +1524,7 @@ int usb_reset_configuration(struct usb_device *dev)
* that the xHCI driver can recalculate the U1/U2 timeouts.
*/
if (usb_disable_lpm(dev)) {
dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__);
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
@ -1583,6 +1608,7 @@ static void usb_release_interface(struct device *dev)
kref_put(&intfc->ref, usb_release_interface_cache);
usb_put_dev(interface_to_usbdev(intf));
of_node_put(dev->of_node);
kfree(intf);
}
@ -1846,7 +1872,7 @@ free_interfaces:
* timeouts.
*/
if (dev->actconfig && usb_disable_lpm(dev)) {
dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__);
mutex_unlock(hcd->bandwidth_mutex);
ret = -ENOMEM;
goto free_interfaces;
@ -1868,6 +1894,7 @@ free_interfaces:
struct usb_interface_cache *intfc;
struct usb_interface *intf;
struct usb_host_interface *alt;
u8 ifnum;
cp->interface[i] = intf = new_interfaces[i];
intfc = cp->intf_cache[i];
@ -1886,11 +1913,17 @@ free_interfaces:
if (!alt)
alt = &intf->altsetting[0];
intf->intf_assoc =
find_iad(dev, cp, alt->desc.bInterfaceNumber);
ifnum = alt->desc.bInterfaceNumber;
intf->intf_assoc = find_iad(dev, cp, ifnum);
intf->cur_altsetting = alt;
usb_enable_interface(dev, intf, true);
intf->dev.parent = &dev->dev;
if (usb_of_has_combined_node(dev)) {
device_set_of_node_from_dev(&intf->dev, &dev->dev);
} else {
intf->dev.of_node = usb_of_get_interface_node(dev,
configuration, ifnum);
}
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
@ -1905,9 +1938,8 @@ free_interfaces:
intf->minor = -1;
device_initialize(&intf->dev);
pm_runtime_no_callbacks(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum,
dev->devpath, configuration, ifnum);
usb_get_dev(dev);
}
kfree(new_interfaces);

View file

@ -3,7 +3,8 @@
* of.c The helpers for hcd device tree support
*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Author: Peter Chen <peter.chen@freescale.com>
* Author: Peter Chen <peter.chen@freescale.com>
* Copyright (C) 2017 Johan Hovold <johan@kernel.org>
*/
#include <linux/of.h>
@ -11,31 +12,99 @@
#include <linux/usb/of.h>
/**
* usb_of_get_child_node - Find the device node match port number
* @parent: the parent device node
* @portnum: the port number which device is connecting
* usb_of_get_device_node() - get a USB device node
* @hub: hub to which device is connected
* @port1: one-based index of port
*
* Find the node from device tree according to its port number.
* Look up the node of a USB device given its parent hub device and one-based
* port number.
*
* Return: A pointer to the node with incremented refcount if found, or
* %NULL otherwise.
*/
struct device_node *usb_of_get_child_node(struct device_node *parent,
int portnum)
struct device_node *usb_of_get_device_node(struct usb_device *hub, int port1)
{
struct device_node *node;
u32 port;
u32 reg;
for_each_child_of_node(parent, node) {
if (!of_property_read_u32(node, "reg", &port)) {
if (port == portnum)
return node;
}
for_each_child_of_node(hub->dev.of_node, node) {
if (of_property_read_u32(node, "reg", &reg))
continue;
if (reg == port1)
return node;
}
return NULL;
}
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
EXPORT_SYMBOL_GPL(usb_of_get_device_node);
/**
* usb_of_has_combined_node() - determine whether a device has a combined node
* @udev: USB device
*
* Determine whether a USB device has a so called combined node which is
* shared with its sole interface. This is the case if and only if the device
* has a node and its decriptors report the following:
*
* 1) bDeviceClass is 0 or 9, and
* 2) bNumConfigurations is 1, and
* 3) bNumInterfaces is 1.
*
* Return: True iff the device has a device node and its descriptors match the
* criteria for a combined node.
*/
bool usb_of_has_combined_node(struct usb_device *udev)
{
struct usb_device_descriptor *ddesc = &udev->descriptor;
struct usb_config_descriptor *cdesc;
if (!udev->dev.of_node)
return false;
switch (ddesc->bDeviceClass) {
case USB_CLASS_PER_INTERFACE:
case USB_CLASS_HUB:
if (ddesc->bNumConfigurations == 1) {
cdesc = &udev->config->desc;
if (cdesc->bNumInterfaces == 1)
return true;
}
}
return false;
}
EXPORT_SYMBOL_GPL(usb_of_has_combined_node);
/**
* usb_of_get_interface_node() - get a USB interface node
* @udev: USB device of interface
* @config: configuration value
* @ifnum: interface number
*
* Look up the node of a USB interface given its USB device, configuration
* value and interface number.
*
* Return: A pointer to the node with incremented refcount if found, or
* %NULL otherwise.
*/
struct device_node *
usb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum)
{
struct device_node *node;
u32 reg[2];
for_each_child_of_node(udev->dev.of_node, node) {
if (of_property_read_u32_array(node, "reg", reg, 2))
continue;
if (reg[0] == ifnum && reg[1] == config)
return node;
}
return NULL;
}
EXPORT_SYMBOL_GPL(usb_of_get_interface_node);
/**
* usb_of_get_companion_dev - Find the companion device

View file

@ -479,9 +479,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;

View file

@ -645,8 +645,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
raw_port = usb_hcd_find_raw_port_number(usb_hcd,
port1);
}
dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
raw_port);
dev->dev.of_node = usb_of_get_device_node(parent, raw_port);
/* hub driver sets up TT records */
}

View file

@ -40,6 +40,7 @@ extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern int usb_set_isoch_delay(struct usb_device *dev);
extern int usb_get_bos_descriptor(struct usb_device *dev);
extern void usb_release_bos_descriptor(struct usb_device *dev);
extern char *usb_cache_string(struct usb_device *udev, int index);

View file

@ -929,6 +929,7 @@ struct dwc2_hsotg {
int irq;
struct clk *clk;
struct reset_control *reset;
struct reset_control *reset_ecc;
unsigned int queuing_high_bandwidth:1;
unsigned int srp_success:1;
@ -971,6 +972,7 @@ struct dwc2_hsotg {
} flags;
struct list_head non_periodic_sched_inactive;
struct list_head non_periodic_sched_waiting;
struct list_head non_periodic_sched_active;
struct list_head *non_periodic_qh_ptr;
struct list_head periodic_sched_inactive;

View file

@ -659,6 +659,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
qh_list_entry)
dev_dbg(hsotg->dev, " %p\n", qh);
dev_dbg(hsotg->dev, " NP waiting sched:\n");
list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
qh_list_entry)
dev_dbg(hsotg->dev, " %p\n", qh);
dev_dbg(hsotg->dev, " NP active sched:\n");
list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
qh_list_entry)
@ -1818,6 +1822,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
{
dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
@ -4998,6 +5003,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
/* Free memory for QH/QTD lists */
dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
@ -5159,6 +5165,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
/* Initialize the non-periodic schedule */
INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
/* Initialize the periodic schedule */

View file

@ -314,12 +314,16 @@ struct dwc2_hs_transfer_time {
* descriptor and indicates original XferSize value for the
* descriptor
* @unreserve_timer: Timer for releasing periodic reservation.
* @wait_timer: Timer used to wait before re-queuing.
* @dwc2_tt: Pointer to our tt info (or NULL if no tt).
* @ttport: Port number within our tt.
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
* @unreserve_pending: True if we planned to unreserve but haven't yet.
* @schedule_low_speed: True if we have a low/full speed component (either the
* host is in low/full speed mode or do_split).
* @want_wait: We should wait before re-queuing; only matters for non-
* periodic transfers and is ignored for periodic ones.
* @wait_timer_cancel: Set to true to cancel the wait_timer.
*
* A Queue Head (QH) holds the static characteristics of an endpoint and
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
@ -354,11 +358,14 @@ struct dwc2_qh {
u32 desc_list_sz;
u32 *n_bytes;
struct timer_list unreserve_timer;
struct timer_list wait_timer;
struct dwc2_tt *dwc_tt;
int ttport;
unsigned tt_buffer_dirty:1;
unsigned unreserve_pending:1;
unsigned schedule_low_speed:1;
unsigned want_wait:1;
unsigned wait_timer_cancel:1;
};
/**
@ -389,6 +396,7 @@ struct dwc2_qh {
* @n_desc: Number of DMA descriptors for this QTD
* @isoc_frame_index_last: Last activated frame (packet) index, used in
* descriptor DMA mode only
* @num_naks: Number of NAKs received on this QTD.
* @urb: URB for this transfer
* @qh: Queue head for this QTD
* @qtd_list_entry: For linking to the QH's list of QTDs
@ -419,6 +427,7 @@ struct dwc2_qtd {
u8 error_count;
u8 n_desc;
u16 isoc_frame_index_last;
u16 num_naks;
struct dwc2_hcd_urb *urb;
struct dwc2_qh *qh;
struct list_head qtd_list_entry;

View file

@ -53,6 +53,12 @@
#include "core.h"
#include "hcd.h"
/*
* If we get this many NAKs on a split transaction we'll slow down
* retransmission. A 1 here means delay after the first NAK.
*/
#define DWC2_NAKS_BEFORE_DELAY 3
/* This function is for debug only */
static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
{
@ -1201,11 +1207,25 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
/*
* Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
* interrupt. Re-start the SSPLIT transfer.
*
* Normally for non-periodic transfers we'll retry right away, but to
* avoid interrupt storms we'll wait before retrying if we've got
* several NAKs. If we didn't do this we'd retry directly from the
* interrupt handler and could end up quickly getting another
* interrupt (another NAK), which we'd retry.
*
* Note that in DMA mode software only gets involved to re-send NAKed
* transfers for split transactions, so we only need to apply this
* delaying logic when handling splits. In non-DMA mode presumably we
* might want a similar delay if someone can demonstrate this problem
* affects that code path too.
*/
if (chan->do_split) {
if (chan->complete_split)
qtd->error_count = 0;
qtd->complete_split = 0;
qtd->num_naks++;
qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
goto handle_nak_done;
}

View file

@ -58,6 +58,9 @@
/* Wait this long before releasing periodic reservation */
#define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
/* If we get a NAK, wait this long before retrying */
#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
/**
* dwc2_periodic_channel_available() - Checks that a channel is available for a
* periodic transfer
@ -1440,6 +1443,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
list_del_init(&qh->qh_list_entry);
}
/**
* dwc2_wait_timer_fn() - Timer function to re-queue after waiting
*
* As per the spec, a NAK indicates that "a function is temporarily unable to
* transmit or receive data, but will eventually be able to do so without need
* of host intervention".
*
* That means that when we encounter a NAK we're supposed to retry.
*
* ...but if we retry right away (from the interrupt handler that saw the NAK)
* then we can end up with an interrupt storm (if the other side keeps NAKing
* us) because on slow enough CPUs it could take us longer to get out of the
* interrupt routine than it takes for the device to send another NAK. That
* leads to a constant stream of NAK interrupts and the CPU locks.
*
* ...so instead of retrying right away in the case of a NAK we'll set a timer
* to retry some time later. This function handles that timer and moves the
* qh back to the "inactive" list, then queues transactions.
*
* @t: Pointer to wait_timer in a qh.
*/
static void dwc2_wait_timer_fn(struct timer_list *t)
{
struct dwc2_qh *qh = from_timer(qh, t, wait_timer);
struct dwc2_hsotg *hsotg = qh->hsotg;
unsigned long flags;
spin_lock_irqsave(&hsotg->lock, flags);
/*
* We'll set wait_timer_cancel to true if we want to cancel this
* operation in dwc2_hcd_qh_unlink().
*/
if (!qh->wait_timer_cancel) {
enum dwc2_transaction_type tr_type;
qh->want_wait = false;
list_move(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
dwc2_hcd_queue_transactions(hsotg, tr_type);
}
spin_unlock_irqrestore(&hsotg->lock, flags);
}
/**
* dwc2_qh_init() - Initializes a QH structure
*
@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
/* Initialize QH */
qh->hsotg = hsotg;
timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0);
qh->ep_type = ep_type;
qh->ep_is_in = ep_is_in;
@ -1628,6 +1681,16 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
dwc2_do_unreserve(hsotg, qh);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
/*
* We don't have the lock so we can safely wait until the wait timer
* finishes. Of course, at this point in time we'd better have set
* wait_timer_active to false so if this timer was still pending it
* won't do anything anyway, but we want it to finish before we free
* memory.
*/
del_timer_sync(&qh->wait_timer);
dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
if (qh->desc_list)
@ -1663,9 +1726,16 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
qh->start_active_frame = hsotg->frame_number;
qh->next_active_frame = qh->start_active_frame;
/* Always start in inactive schedule */
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
if (qh->want_wait) {
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_waiting);
qh->wait_timer_cancel = false;
mod_timer(&qh->wait_timer,
jiffies + DWC2_RETRY_WAIT_DELAY + 1);
} else {
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
}
return 0;
}
@ -1695,6 +1765,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
dev_vdbg(hsotg->dev, "%s()\n", __func__);
/* If the wait_timer is pending, this will stop it from acting */
qh->wait_timer_cancel = true;
if (list_empty(&qh->qh_list_entry))
/* QH is not in a schedule */
return;
@ -1903,7 +1976,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
if (dwc2_qh_is_non_per(qh)) {
dwc2_hcd_qh_unlink(hsotg, qh);
if (!list_empty(&qh->qtd_list))
/* Add back to inactive non-periodic schedule */
/* Add back to inactive/waiting non-periodic schedule */
dwc2_hcd_qh_add(hsotg, qh);
return;
}

View file

@ -221,6 +221,15 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
reset_control_deassert(hsotg->reset);
hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc");
if (IS_ERR(hsotg->reset_ecc)) {
ret = PTR_ERR(hsotg->reset_ecc);
dev_err(hsotg->dev, "error getting reset control for ecc %d\n", ret);
return ret;
}
reset_control_deassert(hsotg->reset_ecc);
/* Set default UTMI width */
hsotg->phyif = GUSBCFG_PHYIF16;
@ -319,6 +328,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
dwc2_lowlevel_hw_disable(hsotg);
reset_control_assert(hsotg->reset);
reset_control_assert(hsotg->reset_ecc);
return 0;
}

View file

@ -147,6 +147,7 @@ static void __dwc3_set_mode(struct work_struct *work)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
phy_calibrate(dwc->usb2_generic_phy);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
@ -945,6 +946,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dev_err(dev, "failed to initialize host\n");
return ret;
}
phy_calibrate(dwc->usb2_generic_phy);
break;
case USB_DR_MODE_OTG:
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
@ -1062,6 +1064,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
&dwc->fladj);
dwc->dis_metastability_quirk = device_property_read_bool(dev,
"snps,dis_metastability_quirk");
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;

View file

@ -796,7 +796,6 @@ struct dwc3_scratchpad_array {
* @usb2_generic_phy: pointer to USB2 PHY
* @usb3_generic_phy: pointer to USB3 PHY
* @ulpi: pointer to ulpi interface
* @isoch_delay: wValue from Set Isochronous Delay request;
* @u2sel: parameter from Set SEL request.
* @u2pel: parameter from Set SEL request.
* @u1sel: parameter from Set SEL request.
@ -857,6 +856,7 @@ struct dwc3_scratchpad_array {
* 1 - -3.5dB de-emphasis
* 2 - No de-emphasis
* 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk.
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
*/
@ -955,7 +955,6 @@ struct dwc3 {
enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
u16 isoch_delay;
u16 u2sel;
u16 u2pel;
u8 u1sel;
@ -1010,6 +1009,8 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
unsigned dis_metastability_quirk:1;
u16 imod_interval;
};

View file

@ -247,6 +247,15 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v,
case USB_DEVICE_TEST_MODE:
s = "Test Mode";
break;
case USB_DEVICE_U1_ENABLE:
s = "U1 Enable";
break;
case USB_DEVICE_U2_ENABLE:
s = "U2 Enable";
break;
case USB_DEVICE_LTM_ENABLE:
s = "LTM Enable";
break;
default:
s = "UNKNOWN";
} s; }),

View file

@ -736,11 +736,7 @@ static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ct
if (wIndex || wLength)
return -EINVAL;
/*
* REVISIT It's unclear from Databook what to do with this
* value. For now, just cache it.
*/
dwc->isoch_delay = wValue;
dwc->gadget.isoch_delay = wValue;
return 0;
}

View file

@ -2005,7 +2005,8 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
* STAR#9000525659: Clock Domain Crossing on DCTL in
* USB 2.0 Mode
*/
if (dwc->revision < DWC3_REVISION_220A) {
if (dwc->revision < DWC3_REVISION_220A &&
!dwc->dis_metastability_quirk) {
reg |= DWC3_DCFG_SUPERSPEED;
} else {
switch (speed) {
@ -3224,7 +3225,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
* is less than super speed because we don't have means, yet, to tell
* composite.c that we are USB 2.0 + LPM ECN.
*/
if (dwc->revision < DWC3_REVISION_220A)
if (dwc->revision < DWC3_REVISION_220A &&
!dwc->dis_metastability_quirk)
dev_info(dwc->dev, "changing max_speed on rev %08x\n",
dwc->revision);

View file

@ -37,12 +37,12 @@ DECLARE_EVENT_CLASS(dwc3_log_io,
);
DEFINE_EVENT(dwc3_log_io, dwc3_readl,
TP_PROTO(void *base, u32 offset, u32 value),
TP_PROTO(void __iomem *base, u32 offset, u32 value),
TP_ARGS(base, offset, value)
);
DEFINE_EVENT(dwc3_log_io, dwc3_writel,
TP_PROTO(void *base, u32 offset, u32 value),
TP_PROTO(void __iomem *base, u32 offset, u32 value),
TP_ARGS(base, offset, value)
);

View file

@ -328,7 +328,7 @@ static void xdbc_mem_init(void)
ep_in = (struct xdbc_ep_context *)&ctx->in;
ep_in->ep_info1 = 0;
ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_OUT_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst));
ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_IN_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst));
ep_in->deq = cpu_to_le64(xdbc.in_seg.dma | xdbc.in_ring.cycle_state);
/* Set DbC context and info registers: */

View file

@ -266,6 +266,7 @@ static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
}
static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
__releases(&ffs->ev.waitq.lock)
{
struct usb_request *req = ffs->ep0req;
int ret;
@ -458,6 +459,7 @@ done_spin:
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
__releases(&ffs->ev.waitq.lock)
{
/*
* n cannot be bigger than ffs->ev.count, which cannot be bigger than
@ -543,6 +545,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
break;
}
/* unlocks spinlock */
return __ffs_ep0_read_events(ffs, buf,
min(n, (size_t)ffs->ev.count));
@ -1246,7 +1249,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
desc = epfile->ep->descs[desc_idx];
spin_unlock_irq(&epfile->ffs->eps_lock);
ret = copy_to_user((void *)value, desc, desc->bLength);
ret = copy_to_user((void __user *)value, desc, desc->bLength);
if (ret)
ret = -EFAULT;
return ret;
@ -2324,7 +2327,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
length, pnl, type);
return -EINVAL;
}
pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl));
if (length != 14 + pnl + pdl) {
pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
length, pnl, pdl, type);
@ -2878,7 +2881,7 @@ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
ext_prop->data_len = le32_to_cpu(*(u32 *)
ext_prop->data_len = le32_to_cpu(*(__le32 *)
usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
length = ext_prop->name_len + ext_prop->data_len + 14;
@ -3700,7 +3703,8 @@ static void ffs_closed(struct ffs_data *ffs)
ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
ffs_dev_unlock();
unregister_gadget_item(ci);
if (test_bit(FFS_FL_BOUND, &ffs->flags))
unregister_gadget_item(ci);
return;
done:
ffs_dev_unlock();

View file

@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/console.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include "u_serial.h"
@ -80,19 +81,11 @@
#define WRITE_BUF_SIZE 8192 /* TX only */
#define GS_CONSOLE_BUF_SIZE 8192
/* circular buffer */
struct gs_buf {
unsigned buf_size;
char *buf_buf;
char *buf_get;
char *buf_put;
};
/* console info */
struct gscons_info {
struct gs_port *port;
struct task_struct *console_thread;
struct gs_buf con_buf;
struct kfifo con_buf;
/* protect the buf and busy flag */
spinlock_t con_lock;
int req_busy;
@ -122,7 +115,7 @@ struct gs_port {
struct list_head write_pool;
int write_started;
int write_allocated;
struct gs_buf port_write_buf;
struct kfifo port_write_buf;
wait_queue_head_t drain_wait; /* wait while writes drain */
bool write_busy;
wait_queue_head_t close_wait;
@ -154,144 +147,6 @@ static struct portmaster {
/*-------------------------------------------------------------------------*/
/* Circular Buffer */
/*
* gs_buf_alloc
*
* Allocate a circular buffer and all associated memory.
*/
static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
{
gb->buf_buf = kmalloc(size, GFP_KERNEL);
if (gb->buf_buf == NULL)
return -ENOMEM;
gb->buf_size = size;
gb->buf_put = gb->buf_buf;
gb->buf_get = gb->buf_buf;
return 0;
}
/*
* gs_buf_free
*
* Free the buffer and all associated memory.
*/
static void gs_buf_free(struct gs_buf *gb)
{
kfree(gb->buf_buf);
gb->buf_buf = NULL;
}
/*
* gs_buf_clear
*
* Clear out all data in the circular buffer.
*/
static void gs_buf_clear(struct gs_buf *gb)
{
gb->buf_get = gb->buf_put;
/* equivalent to a get of all data available */
}
/*
* gs_buf_data_avail
*
* Return the number of bytes of data written into the circular
* buffer.
*/
static unsigned gs_buf_data_avail(struct gs_buf *gb)
{
return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
}
/*
* gs_buf_space_avail
*
* Return the number of bytes of space available in the circular
* buffer.
*/
static unsigned gs_buf_space_avail(struct gs_buf *gb)
{
return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
}
/*
* gs_buf_put
*
* Copy data data from a user buffer and put it into the circular buffer.
* Restrict to the amount of space available.
*
* Return the number of bytes copied.
*/
static unsigned
gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
{
unsigned len;
len = gs_buf_space_avail(gb);
if (count > len)
count = len;
if (count == 0)
return 0;
len = gb->buf_buf + gb->buf_size - gb->buf_put;
if (count > len) {
memcpy(gb->buf_put, buf, len);
memcpy(gb->buf_buf, buf+len, count - len);
gb->buf_put = gb->buf_buf + count - len;
} else {
memcpy(gb->buf_put, buf, count);
if (count < len)
gb->buf_put += count;
else /* count == len */
gb->buf_put = gb->buf_buf;
}
return count;
}
/*
* gs_buf_get
*
* Get data from the circular buffer and copy to the given buffer.
* Restrict to the amount of data available.
*
* Return the number of bytes copied.
*/
static unsigned
gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
{
unsigned len;
len = gs_buf_data_avail(gb);
if (count > len)
count = len;
if (count == 0)
return 0;
len = gb->buf_buf + gb->buf_size - gb->buf_get;
if (count > len) {
memcpy(buf, gb->buf_get, len);
memcpy(buf+len, gb->buf_buf, count - len);
gb->buf_get = gb->buf_buf + count - len;
} else {
memcpy(buf, gb->buf_get, count);
if (count < len)
gb->buf_get += count;
else /* count == len */
gb->buf_get = gb->buf_buf;
}
return count;
}
/*-------------------------------------------------------------------------*/
/* I/O glue between TTY (upper) and USB function (lower) driver layers */
/*
@ -346,11 +201,11 @@ gs_send_packet(struct gs_port *port, char *packet, unsigned size)
{
unsigned len;
len = gs_buf_data_avail(&port->port_write_buf);
len = kfifo_len(&port->port_write_buf);
if (len < size)
size = len;
if (size != 0)
size = gs_buf_get(&port->port_write_buf, packet, size);
size = kfifo_out(&port->port_write_buf, packet, size);
return size;
}
@ -398,7 +253,7 @@ __acquires(&port->port_lock)
req->length = len;
list_del(&req->list);
req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
req->zero = kfifo_is_empty(&port->port_write_buf);
pr_vdebug("ttyGS%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
port->port_num, len, *((u8 *)req->buf),
@ -787,10 +642,11 @@ static int gs_open(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock);
/* allocate circular buffer on first open */
if (port->port_write_buf.buf_buf == NULL) {
if (!kfifo_initialized(&port->port_write_buf)) {
spin_unlock_irq(&port->port_lock);
status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
status = kfifo_alloc(&port->port_write_buf,
WRITE_BUF_SIZE, GFP_KERNEL);
spin_lock_irq(&port->port_lock);
if (status) {
@ -839,7 +695,7 @@ static int gs_writes_finished(struct gs_port *p)
/* return true on disconnect or empty buffer */
spin_lock_irq(&p->port_lock);
cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf);
cond = (p->port_usb == NULL) || !kfifo_len(&p->port_write_buf);
spin_unlock_irq(&p->port_lock);
return cond;
@ -875,7 +731,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
/* wait for circular write buffer to drain, disconnect, or at
* most GS_CLOSE_TIMEOUT seconds; then discard the rest
*/
if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
if (kfifo_len(&port->port_write_buf) > 0 && gser) {
spin_unlock_irq(&port->port_lock);
wait_event_interruptible_timeout(port->drain_wait,
gs_writes_finished(port),
@ -889,9 +745,9 @@ static void gs_close(struct tty_struct *tty, struct file *file)
* let the push tasklet fire again until we're re-opened.
*/
if (gser == NULL)
gs_buf_free(&port->port_write_buf);
kfifo_free(&port->port_write_buf);
else
gs_buf_clear(&port->port_write_buf);
kfifo_reset(&port->port_write_buf);
port->port.tty = NULL;
@ -915,7 +771,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
spin_lock_irqsave(&port->port_lock, flags);
if (count)
count = gs_buf_put(&port->port_write_buf, buf, count);
count = kfifo_in(&port->port_write_buf, buf, count);
/* treat count == 0 as flush_chars() */
if (port->port_usb)
gs_start_tx(port);
@ -934,7 +790,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch)
port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
status = gs_buf_put(&port->port_write_buf, &ch, 1);
status = kfifo_put(&port->port_write_buf, ch);
spin_unlock_irqrestore(&port->port_lock, flags);
return status;
@ -961,7 +817,7 @@ static int gs_write_room(struct tty_struct *tty)
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb)
room = gs_buf_space_avail(&port->port_write_buf);
room = kfifo_avail(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
@ -977,7 +833,7 @@ static int gs_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
spin_lock_irqsave(&port->port_lock, flags);
chars = gs_buf_data_avail(&port->port_write_buf);
chars = kfifo_len(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
@ -1148,7 +1004,7 @@ static int gs_console_thread(void *data)
ep = port->port_usb->in;
spin_lock_irq(&info->con_lock);
count = gs_buf_data_avail(&info->con_buf);
count = kfifo_len(&info->con_buf);
size = ep->maxpacket;
if (count > 0 && !info->req_busy) {
@ -1156,7 +1012,7 @@ static int gs_console_thread(void *data)
if (count < size)
size = count;
xfer = gs_buf_get(&info->con_buf, req->buf, size);
xfer = kfifo_out(&info->con_buf, req->buf, size);
req->length = xfer;
spin_unlock(&info->con_lock);
@ -1192,7 +1048,7 @@ static int gs_console_setup(struct console *co, char *options)
info->req_busy = 0;
spin_lock_init(&info->con_lock);
status = gs_buf_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE);
status = kfifo_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE, GFP_KERNEL);
if (status) {
pr_err("%s: allocate console buffer failed\n", __func__);
return status;
@ -1202,7 +1058,7 @@ static int gs_console_setup(struct console *co, char *options)
co, "gs_console");
if (IS_ERR(info->console_thread)) {
pr_err("%s: cannot create console thread\n", __func__);
gs_buf_free(&info->con_buf);
kfifo_free(&info->con_buf);
return PTR_ERR(info->console_thread);
}
wake_up_process(info->console_thread);
@ -1217,7 +1073,7 @@ static void gs_console_write(struct console *co,
unsigned long flags;
spin_lock_irqsave(&info->con_lock, flags);
gs_buf_put(&info->con_buf, buf, count);
kfifo_in(&info->con_buf, buf, count);
spin_unlock_irqrestore(&info->con_lock, flags);
wake_up_process(info->console_thread);
@ -1256,7 +1112,7 @@ static void gserial_console_exit(void)
unregister_console(&gserial_cons);
if (!IS_ERR_OR_NULL(info->console_thread))
kthread_stop(info->console_thread);
gs_buf_free(&info->con_buf);
kfifo_free(&info->con_buf);
}
#else
@ -1529,7 +1385,7 @@ void gserial_disconnect(struct gserial *gser)
/* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags);
if (port->port.count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf);
kfifo_free(&port->port_write_buf);
gs_free_requests(gser->out, &port->read_pool, NULL);
gs_free_requests(gser->out, &port->read_queue, NULL);
gs_free_requests(gser->in, &port->write_pool, NULL);

View file

@ -1470,7 +1470,6 @@ delegate:
dev->setup_wLength = w_length;
dev->setup_out_ready = 0;
dev->setup_out_error = 0;
value = 0;
/* read DATA stage for OUT right away */
if (unlikely (!dev->setup_in && w_length)) {

View file

@ -102,10 +102,8 @@ static int ncm_do_config(struct usb_configuration *c)
}
f_ncm = usb_get_function(f_ncm_inst);
if (IS_ERR(f_ncm)) {
status = PTR_ERR(f_ncm);
return status;
}
if (IS_ERR(f_ncm))
return PTR_ERR(f_ncm);
status = usb_add_function(c, f_ncm);
if (status < 0) {

View file

@ -2385,10 +2385,8 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
goto out_uninit;
}
if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0,
dev_name(dev), udc) < 0) {
dev_err(dev, "error requesting IRQ #%d\n", irq);
goto out_uninit;
}
dev_name(dev), udc) < 0)
goto report_request_failure;
/* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */
for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
@ -2398,10 +2396,8 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
goto out_uninit;
}
if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0,
dev_name(dev), &udc->iudma[i]) < 0) {
dev_err(dev, "error requesting IRQ #%d\n", irq);
goto out_uninit;
}
dev_name(dev), &udc->iudma[i]) < 0)
goto report_request_failure;
}
bcm63xx_udc_init_debugfs(udc);
@ -2413,6 +2409,10 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
out_uninit:
bcm63xx_uninit_udc_hw(udc);
return rc;
report_request_failure:
dev_err(dev, "error requesting IRQ #%d\n", irq);
goto out_uninit;
}
/**

View file

@ -912,7 +912,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
return 0;
/* "high bandwidth" works only at high speed */
if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp_mult(desc) > 1)
return 0;
switch (type) {
@ -1417,7 +1417,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
/* ------------------------------------------------------------------------- */
static ssize_t usb_udc_srp_store(struct device *dev,
static ssize_t srp_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
@ -1427,9 +1427,9 @@ static ssize_t usb_udc_srp_store(struct device *dev,
return n;
}
static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
static DEVICE_ATTR_WO(srp);
static ssize_t usb_udc_softconn_store(struct device *dev,
static ssize_t soft_connect_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
@ -1453,7 +1453,7 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
return n;
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
static DEVICE_ATTR_WO(soft_connect);
static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf)

View file

@ -925,20 +925,8 @@ static void dummy_udc_set_speed(struct usb_gadget *_gadget,
struct dummy *dum;
dum = gadget_dev_to_dummy(&_gadget->dev);
if (mod_data.is_super_speed)
dum->gadget.speed = min_t(u8, USB_SPEED_SUPER, speed);
else if (mod_data.is_high_speed)
dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, speed);
else
dum->gadget.speed = USB_SPEED_FULL;
dum->gadget.speed = speed;
dummy_udc_update_ep0(dum);
if (dum->gadget.speed < speed)
dev_dbg(udc_dev(dum), "This device can perform faster"
" if you connect it to a %s port...\n",
usb_speed_string(speed));
}
static int dummy_udc_start(struct usb_gadget *g,
@ -2193,8 +2181,6 @@ static int dummy_hub_control(
USB_PORT_STAT_LOW_SPEED;
break;
default:
dum_hcd->dum->gadget.speed =
USB_SPEED_FULL;
break;
}
}

View file

@ -1543,7 +1543,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
udc->ep0_state = WAIT_FOR_SETUP;
break;
case WAIT_FOR_SETUP:
ERR("Unexpect ep0 packets\n");
ERR("Unexpected ep0 packets\n");
break;
default:
ep0stall(udc);

View file

@ -979,8 +979,6 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
max = ep->fifo_size;
do {
is_short = 0;
udccsr = udc_ep_readl(ep, UDCCSR);
if (udccsr & UDCCSR_PC) {
ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
@ -1134,7 +1132,6 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
if (unlikely(!_ep))
return -EINVAL;
dev = udc_usb_ep->dev;
ep = udc_usb_ep->pxa_ep;
if (unlikely(!ep))
return -EINVAL;

View file

@ -225,6 +225,7 @@ DECLARE_EVENT_CLASS(udc_log_req,
__field(unsigned, short_not_ok)
__field(int, status)
__field(int, ret)
__field(struct usb_request *, req)
),
TP_fast_assign(
snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
@ -238,9 +239,10 @@ DECLARE_EVENT_CLASS(udc_log_req,
__entry->short_not_ok = req->short_not_ok;
__entry->status = req->status;
__entry->ret = ret;
__entry->req = req;
),
TP_printk("%s: length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d",
__get_str(name), __entry->actual, __entry->length,
TP_printk("%s: req %p length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d",
__get_str(name),__entry->req, __entry->actual, __entry->length,
__entry->num_mapped_sgs, __entry->num_sgs, __entry->stream_id,
__entry->zero ? "Z" : "z",
__entry->short_not_ok ? "S" : "s",

View file

@ -963,10 +963,8 @@ static struct usb_request *xudc_ep_alloc_request(struct usb_ep *_ep,
gfp_t gfp_flags)
{
struct xusb_ep *ep = to_xusb_ep(_ep);
struct xusb_udc *udc;
struct xusb_req *req;
udc = ep->udc;
req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
return NULL;

View file

@ -27,6 +27,14 @@ config USB_XHCI_HCD
module will be called xhci-hcd.
if USB_XHCI_HCD
config USB_XHCI_DBGCAP
bool "xHCI support for debug capability"
depends on TTY
---help---
Say 'Y' to enable the support for the xHCI debug capability. Make
sure that your xHCI host supports the extended debug capability and
you want a TTY serial device based on the xHCI debug capability
before enabling this option. If unsure, say 'N'.
config USB_XHCI_PCI
tristate

View file

@ -14,6 +14,11 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-y += xhci-trace.o
ifneq ($(CONFIG_USB_XHCI_DBGCAP), )
xhci-hcd-y += xhci-dbgcap.o xhci-dbgtty.o
endif
ifneq ($(CONFIG_USB_XHCI_MTK), )
xhci-hcd-y += xhci-mtk-sch.o
endif

View file

@ -167,7 +167,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
continue;
ret = PTR_ERR(phy);
dev_err(dev, "Can't get PHY device for port %d: %d\n",
if (ret != -EPROBE_DEFER)
dev_err(dev, "Can't get PHY for port %d: %d\n",
i, ret);
goto err_phy;
}

View file

@ -7,7 +7,7 @@
/* Display the ports dedicated to the companion controller */
static ssize_t show_companion(struct device *dev,
static ssize_t companion_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@ -34,7 +34,7 @@ static ssize_t show_companion(struct device *dev,
* Syntax is "[-]portnum", where a leading '-' sign means
* return control of the port to the EHCI controller.
*/
static ssize_t store_companion(struct device *dev,
static ssize_t companion_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@ -59,13 +59,13 @@ static ssize_t store_companion(struct device *dev,
set_owner(ehci, portnum, new_owner);
return count;
}
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
static DEVICE_ATTR_RW(companion);
/*
* Display / Set uframe_periodic_max
*/
static ssize_t show_uframe_periodic_max(struct device *dev,
static ssize_t uframe_periodic_max_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@ -78,7 +78,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev,
}
static ssize_t store_uframe_periodic_max(struct device *dev,
static ssize_t uframe_periodic_max_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@ -143,7 +143,7 @@ out_unlock:
spin_unlock_irqrestore (&ehci->lock, flags);
return ret;
}
static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
static DEVICE_ATTR_RW(uframe_periodic_max);
static inline int create_sysfs_files(struct ehci_hcd *ehci)

View file

@ -1865,11 +1865,9 @@ static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
if (!qh)
goto done;
qh->hw = (struct fotg210_qh_hw *)
dma_pool_alloc(fotg210->qh_pool, flags, &dma);
qh->hw = dma_pool_zalloc(fotg210->qh_pool, flags, &dma);
if (!qh->hw)
goto fail;
memset(qh->hw, 0, sizeof(*qh->hw));
qh->qh_dma = dma;
INIT_LIST_HEAD(&qh->qtd_list);
@ -4121,7 +4119,7 @@ static int itd_urb_transaction(struct fotg210_iso_stream *stream,
} else {
alloc_itd:
spin_unlock_irqrestore(&fotg210->lock, flags);
itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
itd = dma_pool_zalloc(fotg210->itd_pool, mem_flags,
&itd_dma);
spin_lock_irqsave(&fotg210->lock, flags);
if (!itd) {
@ -4131,7 +4129,6 @@ alloc_itd:
}
}
memset(itd, 0, sizeof(*itd));
itd->itd_dma = itd_dma;
list_add(&itd->itd_list, &sched->td_list);
}
@ -4696,7 +4693,7 @@ static void scan_isoc(struct fotg210_hcd *fotg210)
/* Display / Set uframe_periodic_max
*/
static ssize_t show_uframe_periodic_max(struct device *dev,
static ssize_t uframe_periodic_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fotg210_hcd *fotg210;
@ -4708,7 +4705,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev,
}
static ssize_t store_uframe_periodic_max(struct device *dev,
static ssize_t uframe_periodic_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct fotg210_hcd *fotg210;
@ -4775,8 +4772,7 @@ out_unlock:
return ret;
}
static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
store_uframe_periodic_max);
static DEVICE_ATTR_RW(uframe_periodic_max);
static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
{

View file

@ -413,7 +413,7 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
da8xx_ohci = to_da8xx_ohci(hcd);
da8xx_ohci->hcd = hcd;
da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, "usb11");
da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(da8xx_ohci->usb11_clk)) {
error = PTR_ERR(da8xx_ohci->usb11_clk);
if (error != -EPROBE_DEFER)

View file

@ -600,7 +600,7 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->dentry = dentry;
#endif
uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
uhci->frame = dma_zalloc_coherent(uhci_dev(uhci),
UHCI_NUMFRAMES * sizeof(*uhci->frame),
&uhci->frame_dma_handle, GFP_KERNEL);
if (!uhci->frame) {
@ -608,7 +608,6 @@ static int uhci_start(struct usb_hcd *hcd)
"unable to allocate consistent memory for frame list\n");
goto err_alloc_frame;
}
memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame));
uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu),
GFP_KERNEL);

View file

@ -4,6 +4,7 @@
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/clk.h>
#define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
#define PIPE_DEVEP_MASK 0x0007ff00
@ -447,6 +448,8 @@ struct uhci_hcd {
int total_load; /* Sum of array values */
short load[MAX_PHASE]; /* Periodic allocations */
struct clk *clk; /* (optional) clock source */
/* Reset host controller */
void (*reset_hc) (struct uhci_hcd *uhci);
int (*check_and_reset_hc) (struct uhci_hcd *uhci);

View file

@ -89,6 +89,8 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
uhci = hcd_to_uhci(hcd);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
@ -98,8 +100,6 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
uhci = hcd_to_uhci(hcd);
uhci->regs = hcd->regs;
/* Grab some things from the device-tree */
@ -119,13 +119,28 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
"Enabled Aspeed implementation workarounds\n");
}
}
/* Get and enable clock if any specified */
uhci->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uhci->clk)) {
ret = PTR_ERR(uhci->clk);
goto err_rmr;
}
ret = clk_prepare_enable(uhci->clk);
if (ret) {
dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret);
goto err_rmr;
}
ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
if (ret)
goto err_rmr;
goto err_clk;
device_wakeup_enable(hcd->self.controller);
return 0;
err_clk:
clk_disable_unprepare(uhci->clk);
err_rmr:
usb_put_hcd(hcd);
@ -135,7 +150,9 @@ err_rmr:
static int uhci_hcd_platform_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
clk_disable_unprepare(uhci->clk);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);

View file

@ -73,8 +73,7 @@ static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp = urb->hcpriv;
if (!(urb->transfer_flags & URB_NO_FSBR))
urbp->fsbr = 1;
urbp->fsbr = 1;
}
static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp)

View file

@ -90,9 +90,7 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
while (qset->ntds) {
struct whc_qtd *td;
int t;
t = qset->td_start;
td = &qset->qtd[qset->td_start];
status = le32_to_cpu(td->status);

View file

@ -10,267 +10,6 @@
#include "xhci.h"
#define XHCI_INIT_VALUE 0x0
/* Add verbose debugging later, just print everything for now */
void xhci_dbg_regs(struct xhci_hcd *xhci)
{
u32 temp;
xhci_dbg(xhci, "// xHCI capability registers at %p:\n",
xhci->cap_regs);
temp = readl(&xhci->cap_regs->hc_capbase);
xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n",
&xhci->cap_regs->hc_capbase, temp);
xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n",
(unsigned int) HC_LENGTH(temp));
xhci_dbg(xhci, "// HCIVERSION: 0x%x\n",
(unsigned int) HC_VERSION(temp));
xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs);
temp = readl(&xhci->cap_regs->run_regs_off);
xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n",
&xhci->cap_regs->run_regs_off,
(unsigned int) temp & RTSOFF_MASK);
xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs);
temp = readl(&xhci->cap_regs->db_off);
xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp);
xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba);
}
static void xhci_print_cap_regs(struct xhci_hcd *xhci)
{
u32 temp;
u32 hci_version;
xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs);
temp = readl(&xhci->cap_regs->hc_capbase);
hci_version = HC_VERSION(temp);
xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",
(unsigned int) temp);
xhci_dbg(xhci, "CAPLENGTH: 0x%x\n",
(unsigned int) HC_LENGTH(temp));
xhci_dbg(xhci, "HCIVERSION: 0x%x\n", hci_version);
temp = readl(&xhci->cap_regs->hcs_params1);
xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",
(unsigned int) temp);
xhci_dbg(xhci, " Max device slots: %u\n",
(unsigned int) HCS_MAX_SLOTS(temp));
xhci_dbg(xhci, " Max interrupters: %u\n",
(unsigned int) HCS_MAX_INTRS(temp));
xhci_dbg(xhci, " Max ports: %u\n",
(unsigned int) HCS_MAX_PORTS(temp));
temp = readl(&xhci->cap_regs->hcs_params2);
xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n",
(unsigned int) temp);
xhci_dbg(xhci, " Isoc scheduling threshold: %u\n",
(unsigned int) HCS_IST(temp));
xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n",
(unsigned int) HCS_ERST_MAX(temp));
temp = readl(&xhci->cap_regs->hcs_params3);
xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n",
(unsigned int) temp);
xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n",
(unsigned int) HCS_U1_LATENCY(temp));
xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n",
(unsigned int) HCS_U2_LATENCY(temp));
temp = readl(&xhci->cap_regs->hcc_params);
xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp);
xhci_dbg(xhci, " HC generates %s bit addresses\n",
HCC_64BIT_ADDR(temp) ? "64" : "32");
xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n",
HCC_CFC(temp) ? "has" : "hasn't");
xhci_dbg(xhci, " HC %s generate Stopped - Short Package event\n",
HCC_SPC(temp) ? "can" : "can't");
/* FIXME */
xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n");
temp = readl(&xhci->cap_regs->run_regs_off);
xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
/* xhci 1.1 controllers have the HCCPARAMS2 register */
if (hci_version > 0x100) {
temp = readl(&xhci->cap_regs->hcc_params2);
xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp);
xhci_dbg(xhci, " HC %s Force save context capability",
HCC2_FSC(temp) ? "supports" : "doesn't support");
xhci_dbg(xhci, " HC %s Large ESIT Payload Capability",
HCC2_LEC(temp) ? "supports" : "doesn't support");
xhci_dbg(xhci, " HC %s Extended TBC capability",
HCC2_ETC(temp) ? "supports" : "doesn't support");
}
}
static void xhci_print_command_reg(struct xhci_hcd *xhci)
{
u32 temp;
temp = readl(&xhci->op_regs->command);
xhci_dbg(xhci, "USBCMD 0x%x:\n", temp);
xhci_dbg(xhci, " HC is %s\n",
(temp & CMD_RUN) ? "running" : "being stopped");
xhci_dbg(xhci, " HC has %sfinished hard reset\n",
(temp & CMD_RESET) ? "not " : "");
xhci_dbg(xhci, " Event Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
(temp & CMD_HSEIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " HC has %sfinished light reset\n",
(temp & CMD_LRESET) ? "not " : "");
}
static void xhci_print_status(struct xhci_hcd *xhci)
{
u32 temp;
temp = readl(&xhci->op_regs->status);
xhci_dbg(xhci, "USBSTS 0x%x:\n", temp);
xhci_dbg(xhci, " Event ring is %sempty\n",
(temp & STS_EINT) ? "not " : "");
xhci_dbg(xhci, " %sHost System Error\n",
(temp & STS_FATAL) ? "WARNING: " : "No ");
xhci_dbg(xhci, " HC is %s\n",
(temp & STS_HALT) ? "halted" : "running");
}
static void xhci_print_op_regs(struct xhci_hcd *xhci)
{
xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs);
xhci_print_command_reg(xhci);
xhci_print_status(xhci);
}
static void xhci_print_ports(struct xhci_hcd *xhci)
{
__le32 __iomem *addr;
int i, j;
int ports;
char *names[NUM_PORT_REGS] = {
"status",
"power",
"link",
"reserved",
};
ports = HCS_MAX_PORTS(xhci->hcs_params1);
addr = &xhci->op_regs->port_status_base;
for (i = 0; i < ports; i++) {
for (j = 0; j < NUM_PORT_REGS; j++) {
xhci_dbg(xhci, "%p port %s reg = 0x%x\n",
addr, names[j],
(unsigned int) readl(addr));
addr++;
}
}
}
void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)
{
struct xhci_intr_reg __iomem *ir_set = &xhci->run_regs->ir_set[set_num];
void __iomem *addr;
u32 temp;
u64 temp_64;
addr = &ir_set->irq_pending;
temp = readl(addr);
if (temp == XHCI_INIT_VALUE)
return;
xhci_dbg(xhci, " %p: ir_set[%i]\n", ir_set, set_num);
xhci_dbg(xhci, " %p: ir_set.pending = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->irq_control;
temp = readl(addr);
xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->erst_size;
temp = readl(addr);
xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->rsvd;
temp = readl(addr);
if (temp != XHCI_INIT_VALUE)
xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n",
addr, (unsigned int)temp);
addr = &ir_set->erst_base;
temp_64 = xhci_read_64(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n",
addr, temp_64);
addr = &ir_set->erst_dequeue;
temp_64 = xhci_read_64(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n",
addr, temp_64);
}
void xhci_print_run_regs(struct xhci_hcd *xhci)
{
u32 temp;
int i;
xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs);
temp = readl(&xhci->run_regs->microframe_index);
xhci_dbg(xhci, " %p: Microframe index = 0x%x\n",
&xhci->run_regs->microframe_index,
(unsigned int) temp);
for (i = 0; i < 7; i++) {
temp = readl(&xhci->run_regs->rsvd[i]);
if (temp != XHCI_INIT_VALUE)
xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n",
&xhci->run_regs->rsvd[i],
i, (unsigned int) temp);
}
}
void xhci_print_registers(struct xhci_hcd *xhci)
{
xhci_print_cap_regs(xhci);
xhci_print_op_regs(xhci);
xhci_print_ports(xhci);
}
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
{
u64 addr = erst->erst_dma_addr;
int i;
struct xhci_erst_entry *entry;
for (i = 0; i < erst->num_entries; i++) {
entry = &erst->entries[i];
xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n",
addr,
lower_32_bits(le64_to_cpu(entry->seg_addr)),
upper_32_bits(le64_to_cpu(entry->seg_addr)),
le32_to_cpu(entry->seg_size),
le32_to_cpu(entry->rsvd));
addr += sizeof(*entry);
}
}
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
{
u64 val;
val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n",
lower_32_bits(val));
xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n",
upper_32_bits(val));
}
char *xhci_get_slot_state(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx)
{

View file

@ -0,0 +1,996 @@
/**
* xhci-dbgcap.c - xHCI debug capability support
*
* Copyright (C) 2017 Intel Corporation
*
* Author: Lu Baolu <baolu.lu@linux.intel.com>
*/
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/nls.h>
#include "xhci.h"
#include "xhci-trace.h"
#include "xhci-dbgcap.h"
static inline void *
dbc_dma_alloc_coherent(struct xhci_hcd *xhci, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
{
void *vaddr;
vaddr = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, dma_handle, flags);
memset(vaddr, 0, size);
return vaddr;
}
static inline void
dbc_dma_free_coherent(struct xhci_hcd *xhci, size_t size,
void *cpu_addr, dma_addr_t dma_handle)
{
if (cpu_addr)
dma_free_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, cpu_addr, dma_handle);
}
static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings)
{
struct usb_string_descriptor *s_desc;
u32 string_length;
/* Serial string: */
s_desc = (struct usb_string_descriptor *)strings->serial;
utf8s_to_utf16s(DBC_STRING_SERIAL, strlen(DBC_STRING_SERIAL),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_SERIAL) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length = s_desc->bLength;
string_length <<= 8;
/* Product string: */
s_desc = (struct usb_string_descriptor *)strings->product;
utf8s_to_utf16s(DBC_STRING_PRODUCT, strlen(DBC_STRING_PRODUCT),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_PRODUCT) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* Manufacture string: */
s_desc = (struct usb_string_descriptor *)strings->manufacturer;
utf8s_to_utf16s(DBC_STRING_MANUFACTURER,
strlen(DBC_STRING_MANUFACTURER),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_MANUFACTURER) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* String0: */
strings->string0[0] = 4;
strings->string0[1] = USB_DT_STRING;
strings->string0[2] = 0x09;
strings->string0[3] = 0x04;
string_length += 4;
return string_length;
}
static void xhci_dbc_init_contexts(struct xhci_hcd *xhci, u32 string_length)
{
struct xhci_dbc *dbc;
struct dbc_info_context *info;
struct xhci_ep_ctx *ep_ctx;
u32 dev_info;
dma_addr_t deq, dma;
unsigned int max_burst;
dbc = xhci->dbc;
if (!dbc)
return;
/* Populate info Context: */
info = (struct dbc_info_context *)dbc->ctx->bytes;
dma = dbc->string_dma;
info->string0 = cpu_to_le64(dma);
info->manufacturer = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH);
info->product = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2);
info->serial = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
info->length = cpu_to_le32(string_length);
/* Populate bulk out endpoint context: */
ep_ctx = dbc_bulkout_ctx(dbc);
max_burst = DBC_CTRL_MAXBURST(readl(&dbc->regs->control));
deq = dbc_bulkout_enq(dbc);
ep_ctx->ep_info = 0;
ep_ctx->ep_info2 = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst);
ep_ctx->deq = cpu_to_le64(deq | dbc->ring_out->cycle_state);
/* Populate bulk in endpoint context: */
ep_ctx = dbc_bulkin_ctx(dbc);
deq = dbc_bulkin_enq(dbc);
ep_ctx->ep_info = 0;
ep_ctx->ep_info2 = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst);
ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state);
/* Set DbC context and info registers: */
xhci_write_64(xhci, dbc->ctx->dma, &dbc->regs->dccp);
dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL);
writel(dev_info, &dbc->regs->devinfo1);
dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID);
writel(dev_info, &dbc->regs->devinfo2);
}
static void xhci_dbc_giveback(struct dbc_request *req, int status)
__releases(&dbc->lock)
__acquires(&dbc->lock)
{
struct dbc_ep *dep = req->dep;
struct xhci_dbc *dbc = dep->dbc;
struct xhci_hcd *xhci = dbc->xhci;
struct device *dev = xhci_to_hcd(dbc->xhci)->self.sysdev;
list_del_init(&req->list_pending);
req->trb_dma = 0;
req->trb = NULL;
if (req->status == -EINPROGRESS)
req->status = status;
trace_xhci_dbc_giveback_request(req);
dma_unmap_single(dev,
req->dma,
req->length,
dbc_ep_dma_direction(dep));
/* Give back the transfer request: */
spin_unlock(&dbc->lock);
req->complete(xhci, req);
spin_lock(&dbc->lock);
}
static void xhci_dbc_flush_single_request(struct dbc_request *req)
{
union xhci_trb *trb = req->trb;
trb->generic.field[0] = 0;
trb->generic.field[1] = 0;
trb->generic.field[2] = 0;
trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(TRB_TR_NOOP));
xhci_dbc_giveback(req, -ESHUTDOWN);
}
static void xhci_dbc_flush_endpoint_requests(struct dbc_ep *dep)
{
struct dbc_request *req, *tmp;
list_for_each_entry_safe(req, tmp, &dep->list_pending, list_pending)
xhci_dbc_flush_single_request(req);
}
static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc)
{
xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]);
xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]);
}
struct dbc_request *
dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags)
{
struct dbc_request *req;
req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
return NULL;
req->dep = dep;
INIT_LIST_HEAD(&req->list_pending);
INIT_LIST_HEAD(&req->list_pool);
req->direction = dep->direction;
trace_xhci_dbc_alloc_request(req);
return req;
}
void
dbc_free_request(struct dbc_ep *dep, struct dbc_request *req)
{
trace_xhci_dbc_free_request(req);
kfree(req);
}
static void
xhci_dbc_queue_trb(struct xhci_ring *ring, u32 field1,
u32 field2, u32 field3, u32 field4)
{
union xhci_trb *trb, *next;
trb = ring->enqueue;
trb->generic.field[0] = cpu_to_le32(field1);
trb->generic.field[1] = cpu_to_le32(field2);
trb->generic.field[2] = cpu_to_le32(field3);
trb->generic.field[3] = cpu_to_le32(field4);
trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic);
ring->num_trbs_free--;
next = ++(ring->enqueue);
if (TRB_TYPE_LINK_LE32(next->link.control)) {
next->link.control ^= cpu_to_le32(TRB_CYCLE);
ring->enqueue = ring->enq_seg->trbs;
ring->cycle_state ^= 1;
}
}
static int xhci_dbc_queue_bulk_tx(struct dbc_ep *dep,
struct dbc_request *req)
{
u64 addr;
union xhci_trb *trb;
unsigned int num_trbs;
struct xhci_dbc *dbc = dep->dbc;
struct xhci_ring *ring = dep->ring;
u32 length, control, cycle;
num_trbs = count_trbs(req->dma, req->length);
WARN_ON(num_trbs != 1);
if (ring->num_trbs_free < num_trbs)
return -EBUSY;
addr = req->dma;
trb = ring->enqueue;
cycle = ring->cycle_state;
length = TRB_LEN(req->length);
control = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
if (cycle)
control &= cpu_to_le32(~TRB_CYCLE);
else
control |= cpu_to_le32(TRB_CYCLE);
req->trb = ring->enqueue;
req->trb_dma = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
xhci_dbc_queue_trb(ring,
lower_32_bits(addr),
upper_32_bits(addr),
length, control);
/*
* Add a barrier between writes of trb fields and flipping
* the cycle bit:
*/
wmb();
if (cycle)
trb->generic.field[3] |= cpu_to_le32(TRB_CYCLE);
else
trb->generic.field[3] &= cpu_to_le32(~TRB_CYCLE);
writel(DBC_DOOR_BELL_TARGET(dep->direction), &dbc->regs->doorbell);
return 0;
}
static int
dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req)
{
int ret;
struct device *dev;
struct xhci_dbc *dbc = dep->dbc;
struct xhci_hcd *xhci = dbc->xhci;
dev = xhci_to_hcd(xhci)->self.sysdev;
if (!req->length || !req->buf)
return -EINVAL;
req->actual = 0;
req->status = -EINPROGRESS;
req->dma = dma_map_single(dev,
req->buf,
req->length,
dbc_ep_dma_direction(dep));
if (dma_mapping_error(dev, req->dma)) {
xhci_err(xhci, "failed to map buffer\n");
return -EFAULT;
}
ret = xhci_dbc_queue_bulk_tx(dep, req);
if (ret) {
xhci_err(xhci, "failed to queue trbs\n");
dma_unmap_single(dev,
req->dma,
req->length,
dbc_ep_dma_direction(dep));
return -EFAULT;
}
list_add_tail(&req->list_pending, &dep->list_pending);
return 0;
}
int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req,
gfp_t gfp_flags)
{
struct xhci_dbc *dbc = dep->dbc;
int ret = -ESHUTDOWN;
spin_lock(&dbc->lock);
if (dbc->state == DS_CONFIGURED)
ret = dbc_ep_do_queue(dep, req);
spin_unlock(&dbc->lock);
mod_delayed_work(system_wq, &dbc->event_work, 0);
trace_xhci_dbc_queue_request(req);
return ret;
}
static inline void xhci_dbc_do_eps_init(struct xhci_hcd *xhci, bool direction)
{
struct dbc_ep *dep;
struct xhci_dbc *dbc = xhci->dbc;
dep = &dbc->eps[direction];
dep->dbc = dbc;
dep->direction = direction;
dep->ring = direction ? dbc->ring_in : dbc->ring_out;
INIT_LIST_HEAD(&dep->list_pending);
}
static void xhci_dbc_eps_init(struct xhci_hcd *xhci)
{
xhci_dbc_do_eps_init(xhci, BULK_OUT);
xhci_dbc_do_eps_init(xhci, BULK_IN);
}
static void xhci_dbc_eps_exit(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
memset(dbc->eps, 0, sizeof(struct dbc_ep) * ARRAY_SIZE(dbc->eps));
}
static int xhci_dbc_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
int ret;
dma_addr_t deq;
u32 string_length;
struct xhci_dbc *dbc = xhci->dbc;
/* Allocate various rings for events and transfers: */
dbc->ring_evt = xhci_ring_alloc(xhci, 1, 1, TYPE_EVENT, 0, flags);
if (!dbc->ring_evt)
goto evt_fail;
dbc->ring_in = xhci_ring_alloc(xhci, 1, 1, TYPE_BULK, 0, flags);
if (!dbc->ring_in)
goto in_fail;
dbc->ring_out = xhci_ring_alloc(xhci, 1, 1, TYPE_BULK, 0, flags);
if (!dbc->ring_out)
goto out_fail;
/* Allocate and populate ERST: */
ret = xhci_alloc_erst(xhci, dbc->ring_evt, &dbc->erst, flags);
if (ret)
goto erst_fail;
/* Allocate context data structure: */
dbc->ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
if (!dbc->ctx)
goto ctx_fail;
/* Allocate the string table: */
dbc->string_size = sizeof(struct dbc_str_descs);
dbc->string = dbc_dma_alloc_coherent(xhci,
dbc->string_size,
&dbc->string_dma,
flags);
if (!dbc->string)
goto string_fail;
/* Setup ERST register: */
writel(dbc->erst.erst_size, &dbc->regs->ersts);
xhci_write_64(xhci, dbc->erst.erst_dma_addr, &dbc->regs->erstba);
deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg,
dbc->ring_evt->dequeue);
xhci_write_64(xhci, deq, &dbc->regs->erdp);
/* Setup strings and contexts: */
string_length = xhci_dbc_populate_strings(dbc->string);
xhci_dbc_init_contexts(xhci, string_length);
mmiowb();
xhci_dbc_eps_init(xhci);
dbc->state = DS_INITIALIZED;
return 0;
string_fail:
xhci_free_container_ctx(xhci, dbc->ctx);
dbc->ctx = NULL;
ctx_fail:
xhci_free_erst(xhci, &dbc->erst);
erst_fail:
xhci_ring_free(xhci, dbc->ring_out);
dbc->ring_out = NULL;
out_fail:
xhci_ring_free(xhci, dbc->ring_in);
dbc->ring_in = NULL;
in_fail:
xhci_ring_free(xhci, dbc->ring_evt);
dbc->ring_evt = NULL;
evt_fail:
return -ENOMEM;
}
static void xhci_dbc_mem_cleanup(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
if (!dbc)
return;
xhci_dbc_eps_exit(xhci);
if (dbc->string) {
dbc_dma_free_coherent(xhci,
dbc->string_size,
dbc->string, dbc->string_dma);
dbc->string = NULL;
}
xhci_free_container_ctx(xhci, dbc->ctx);
dbc->ctx = NULL;
xhci_free_erst(xhci, &dbc->erst);
xhci_ring_free(xhci, dbc->ring_out);
xhci_ring_free(xhci, dbc->ring_in);
xhci_ring_free(xhci, dbc->ring_evt);
dbc->ring_in = NULL;
dbc->ring_out = NULL;
dbc->ring_evt = NULL;
}
static int xhci_do_dbc_start(struct xhci_hcd *xhci)
{
int ret;
u32 ctrl;
struct xhci_dbc *dbc = xhci->dbc;
if (dbc->state != DS_DISABLED)
return -EINVAL;
writel(0, &dbc->regs->control);
ret = xhci_handshake(&dbc->regs->control,
DBC_CTRL_DBC_ENABLE,
0, 1000);
if (ret)
return ret;
ret = xhci_dbc_mem_init(xhci, GFP_ATOMIC);
if (ret)
return ret;
ctrl = readl(&dbc->regs->control);
writel(ctrl | DBC_CTRL_DBC_ENABLE | DBC_CTRL_PORT_ENABLE,
&dbc->regs->control);
ret = xhci_handshake(&dbc->regs->control,
DBC_CTRL_DBC_ENABLE,
DBC_CTRL_DBC_ENABLE, 1000);
if (ret)
return ret;
dbc->state = DS_ENABLED;
return 0;
}
static void xhci_do_dbc_stop(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
if (dbc->state == DS_DISABLED)
return;
writel(0, &dbc->regs->control);
xhci_dbc_mem_cleanup(xhci);
dbc->state = DS_DISABLED;
}
static int xhci_dbc_start(struct xhci_hcd *xhci)
{
int ret;
struct xhci_dbc *dbc = xhci->dbc;
WARN_ON(!dbc);
pm_runtime_get_sync(xhci_to_hcd(xhci)->self.controller);
spin_lock(&dbc->lock);
ret = xhci_do_dbc_start(xhci);
spin_unlock(&dbc->lock);
if (ret) {
pm_runtime_put(xhci_to_hcd(xhci)->self.controller);
return ret;
}
return mod_delayed_work(system_wq, &dbc->event_work, 1);
}
static void xhci_dbc_stop(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
struct dbc_port *port = &dbc->port;
WARN_ON(!dbc);
cancel_delayed_work_sync(&dbc->event_work);
if (port->registered)
xhci_dbc_tty_unregister_device(xhci);
spin_lock(&dbc->lock);
xhci_do_dbc_stop(xhci);
spin_unlock(&dbc->lock);
pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller);
}
static void
dbc_handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
{
u32 portsc;
struct xhci_dbc *dbc = xhci->dbc;
portsc = readl(&dbc->regs->portsc);
if (portsc & DBC_PORTSC_CONN_CHANGE)
xhci_info(xhci, "DbC port connect change\n");
if (portsc & DBC_PORTSC_RESET_CHANGE)
xhci_info(xhci, "DbC port reset change\n");
if (portsc & DBC_PORTSC_LINK_CHANGE)
xhci_info(xhci, "DbC port link status change\n");
if (portsc & DBC_PORTSC_CONFIG_CHANGE)
xhci_info(xhci, "DbC config error change\n");
/* Port reset change bit will be cleared in other place: */
writel(portsc & ~DBC_PORTSC_RESET_CHANGE, &dbc->regs->portsc);
}
static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event)
{
struct dbc_ep *dep;
struct xhci_ring *ring;
int ep_id;
int status;
u32 comp_code;
size_t remain_length;
struct dbc_request *req = NULL, *r;
comp_code = GET_COMP_CODE(le32_to_cpu(event->generic.field[2]));
remain_length = EVENT_TRB_LEN(le32_to_cpu(event->generic.field[2]));
ep_id = TRB_TO_EP_ID(le32_to_cpu(event->generic.field[3]));
dep = (ep_id == EPID_OUT) ?
get_out_ep(xhci) : get_in_ep(xhci);
ring = dep->ring;
switch (comp_code) {
case COMP_SUCCESS:
remain_length = 0;
/* FALLTHROUGH */
case COMP_SHORT_PACKET:
status = 0;
break;
case COMP_TRB_ERROR:
case COMP_BABBLE_DETECTED_ERROR:
case COMP_USB_TRANSACTION_ERROR:
case COMP_STALL_ERROR:
xhci_warn(xhci, "tx error %d detected\n", comp_code);
status = -comp_code;
break;
default:
xhci_err(xhci, "unknown tx error %d\n", comp_code);
status = -comp_code;
break;
}
/* Match the pending request: */
list_for_each_entry(r, &dep->list_pending, list_pending) {
if (r->trb_dma == event->trans_event.buffer) {
req = r;
break;
}
}
if (!req) {
xhci_warn(xhci, "no matched request\n");
return;
}
trace_xhci_dbc_handle_transfer(ring, &req->trb->generic);
ring->num_trbs_free++;
req->actual = req->length - remain_length;
xhci_dbc_giveback(req, status);
}
static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
{
dma_addr_t deq;
struct dbc_ep *dep;
union xhci_trb *evt;
u32 ctrl, portsc;
struct xhci_hcd *xhci = dbc->xhci;
bool update_erdp = false;
/* DbC state machine: */
switch (dbc->state) {
case DS_DISABLED:
case DS_INITIALIZED:
return EVT_ERR;
case DS_ENABLED:
portsc = readl(&dbc->regs->portsc);
if (portsc & DBC_PORTSC_CONN_STATUS) {
dbc->state = DS_CONNECTED;
xhci_info(xhci, "DbC connected\n");
}
return EVT_DONE;
case DS_CONNECTED:
ctrl = readl(&dbc->regs->control);
if (ctrl & DBC_CTRL_DBC_RUN) {
dbc->state = DS_CONFIGURED;
xhci_info(xhci, "DbC configured\n");
portsc = readl(&dbc->regs->portsc);
writel(portsc, &dbc->regs->portsc);
return EVT_GSER;
}
return EVT_DONE;
case DS_CONFIGURED:
/* Handle cable unplug event: */
portsc = readl(&dbc->regs->portsc);
if (!(portsc & DBC_PORTSC_PORT_ENABLED) &&
!(portsc & DBC_PORTSC_CONN_STATUS)) {
xhci_info(xhci, "DbC cable unplugged\n");
dbc->state = DS_ENABLED;
xhci_dbc_flush_reqests(dbc);
return EVT_DISC;
}
/* Handle debug port reset event: */
if (portsc & DBC_PORTSC_RESET_CHANGE) {
xhci_info(xhci, "DbC port reset\n");
writel(portsc, &dbc->regs->portsc);
dbc->state = DS_ENABLED;
xhci_dbc_flush_reqests(dbc);
return EVT_DISC;
}
/* Handle endpoint stall event: */
ctrl = readl(&dbc->regs->control);
if ((ctrl & DBC_CTRL_HALT_IN_TR) ||
(ctrl & DBC_CTRL_HALT_OUT_TR)) {
xhci_info(xhci, "DbC Endpoint stall\n");
dbc->state = DS_STALLED;
if (ctrl & DBC_CTRL_HALT_IN_TR) {
dep = get_in_ep(xhci);
xhci_dbc_flush_endpoint_requests(dep);
}
if (ctrl & DBC_CTRL_HALT_OUT_TR) {
dep = get_out_ep(xhci);
xhci_dbc_flush_endpoint_requests(dep);
}
return EVT_DONE;
}
/* Clear DbC run change bit: */
if (ctrl & DBC_CTRL_DBC_RUN_CHANGE) {
writel(ctrl, &dbc->regs->control);
ctrl = readl(&dbc->regs->control);
}
break;
case DS_STALLED:
ctrl = readl(&dbc->regs->control);
if (!(ctrl & DBC_CTRL_HALT_IN_TR) &&
!(ctrl & DBC_CTRL_HALT_OUT_TR) &&
(ctrl & DBC_CTRL_DBC_RUN)) {
dbc->state = DS_CONFIGURED;
break;
}
return EVT_DONE;
default:
xhci_err(xhci, "Unknown DbC state %d\n", dbc->state);
break;
}
/* Handle the events in the event ring: */
evt = dbc->ring_evt->dequeue;
while ((le32_to_cpu(evt->event_cmd.flags) & TRB_CYCLE) ==
dbc->ring_evt->cycle_state) {
/*
* Add a barrier between reading the cycle flag and any
* reads of the event's flags/data below:
*/
rmb();
trace_xhci_dbc_handle_event(dbc->ring_evt, &evt->generic);
switch (le32_to_cpu(evt->event_cmd.flags) & TRB_TYPE_BITMASK) {
case TRB_TYPE(TRB_PORT_STATUS):
dbc_handle_port_status(xhci, evt);
break;
case TRB_TYPE(TRB_TRANSFER):
dbc_handle_xfer_event(xhci, evt);
break;
default:
break;
}
inc_deq(xhci, dbc->ring_evt);
evt = dbc->ring_evt->dequeue;
update_erdp = true;
}
/* Update event ring dequeue pointer: */
if (update_erdp) {
deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg,
dbc->ring_evt->dequeue);
xhci_write_64(xhci, deq, &dbc->regs->erdp);
}
return EVT_DONE;
}
static void xhci_dbc_handle_events(struct work_struct *work)
{
int ret;
enum evtreturn evtr;
struct xhci_dbc *dbc;
struct xhci_hcd *xhci;
dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
xhci = dbc->xhci;
spin_lock(&dbc->lock);
evtr = xhci_dbc_do_handle_events(dbc);
spin_unlock(&dbc->lock);
switch (evtr) {
case EVT_GSER:
ret = xhci_dbc_tty_register_device(xhci);
if (ret) {
xhci_err(xhci, "failed to alloc tty device\n");
break;
}
xhci_info(xhci, "DbC now attached to /dev/ttyDBC0\n");
break;
case EVT_DISC:
xhci_dbc_tty_unregister_device(xhci);
break;
case EVT_DONE:
break;
default:
xhci_info(xhci, "stop handling dbc events\n");
return;
}
mod_delayed_work(system_wq, &dbc->event_work, 1);
}
static void xhci_do_dbc_exit(struct xhci_hcd *xhci)
{
unsigned long flags;
spin_lock_irqsave(&xhci->lock, flags);
kfree(xhci->dbc);
xhci->dbc = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
}
static int xhci_do_dbc_init(struct xhci_hcd *xhci)
{
u32 reg;
struct xhci_dbc *dbc;
unsigned long flags;
void __iomem *base;
int dbc_cap_offs;
base = &xhci->cap_regs->hc_capbase;
dbc_cap_offs = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_DEBUG);
if (!dbc_cap_offs)
return -ENODEV;
dbc = kzalloc(sizeof(*dbc), GFP_KERNEL);
if (!dbc)
return -ENOMEM;
dbc->regs = base + dbc_cap_offs;
/* We will avoid using DbC in xhci driver if it's in use. */
reg = readl(&dbc->regs->control);
if (reg & DBC_CTRL_DBC_ENABLE) {
kfree(dbc);
return -EBUSY;
}
spin_lock_irqsave(&xhci->lock, flags);
if (xhci->dbc) {
spin_unlock_irqrestore(&xhci->lock, flags);
kfree(dbc);
return -EBUSY;
}
xhci->dbc = dbc;
spin_unlock_irqrestore(&xhci->lock, flags);
dbc->xhci = xhci;
INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
spin_lock_init(&dbc->lock);
return 0;
}
static ssize_t dbc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
const char *p;
struct xhci_dbc *dbc;
struct xhci_hcd *xhci;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
switch (dbc->state) {
case DS_DISABLED:
p = "disabled";
break;
case DS_INITIALIZED:
p = "initialized";
break;
case DS_ENABLED:
p = "enabled";
break;
case DS_CONNECTED:
p = "connected";
break;
case DS_CONFIGURED:
p = "configured";
break;
case DS_STALLED:
p = "stalled";
break;
default:
p = "unknown";
}
return sprintf(buf, "%s\n", p);
}
static ssize_t dbc_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct xhci_dbc *dbc;
struct xhci_hcd *xhci;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
if (!strncmp(buf, "enable", 6))
xhci_dbc_start(xhci);
else if (!strncmp(buf, "disable", 7))
xhci_dbc_stop(xhci);
else
return -EINVAL;
return count;
}
static DEVICE_ATTR_RW(dbc);
int xhci_dbc_init(struct xhci_hcd *xhci)
{
int ret;
struct device *dev = xhci_to_hcd(xhci)->self.controller;
ret = xhci_do_dbc_init(xhci);
if (ret)
goto init_err3;
ret = xhci_dbc_tty_register_driver(xhci);
if (ret)
goto init_err2;
ret = device_create_file(dev, &dev_attr_dbc);
if (ret)
goto init_err1;
return 0;
init_err1:
xhci_dbc_tty_unregister_driver();
init_err2:
xhci_do_dbc_exit(xhci);
init_err3:
return ret;
}
void xhci_dbc_exit(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
if (!xhci->dbc)
return;
device_remove_file(dev, &dev_attr_dbc);
xhci_dbc_tty_unregister_driver();
xhci_dbc_stop(xhci);
xhci_do_dbc_exit(xhci);
}
#ifdef CONFIG_PM
int xhci_dbc_suspend(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
if (!dbc)
return 0;
if (dbc->state == DS_CONFIGURED)
dbc->resume_required = 1;
xhci_dbc_stop(xhci);
return 0;
}
int xhci_dbc_resume(struct xhci_hcd *xhci)
{
int ret = 0;
struct xhci_dbc *dbc = xhci->dbc;
if (!dbc)
return 0;
if (dbc->resume_required) {
dbc->resume_required = 0;
xhci_dbc_start(xhci);
}
return ret;
}
#endif /* CONFIG_PM */

View file

@ -0,0 +1,229 @@
/**
* xhci-dbgcap.h - xHCI debug capability support
*
* Copyright (C) 2017 Intel Corporation
*
* Author: Lu Baolu <baolu.lu@linux.intel.com>
*/
#ifndef __LINUX_XHCI_DBGCAP_H
#define __LINUX_XHCI_DBGCAP_H
#include <linux/tty.h>
#include <linux/kfifo.h>
struct dbc_regs {
__le32 capability;
__le32 doorbell;
__le32 ersts; /* Event Ring Segment Table Size*/
__le32 __reserved_0; /* 0c~0f reserved bits */
__le64 erstba; /* Event Ring Segment Table Base Address */
__le64 erdp; /* Event Ring Dequeue Pointer */
__le32 control;
__le32 status;
__le32 portsc; /* Port status and control */
__le32 __reserved_1; /* 2b~28 reserved bits */
__le64 dccp; /* Debug Capability Context Pointer */
__le32 devinfo1; /* Device Descriptor Info Register 1 */
__le32 devinfo2; /* Device Descriptor Info Register 2 */
};
struct dbc_info_context {
__le64 string0;
__le64 manufacturer;
__le64 product;
__le64 serial;
__le32 length;
__le32 __reserved_0[7];
};
#define DBC_CTRL_DBC_RUN BIT(0)
#define DBC_CTRL_PORT_ENABLE BIT(1)
#define DBC_CTRL_HALT_OUT_TR BIT(2)
#define DBC_CTRL_HALT_IN_TR BIT(3)
#define DBC_CTRL_DBC_RUN_CHANGE BIT(4)
#define DBC_CTRL_DBC_ENABLE BIT(31)
#define DBC_CTRL_MAXBURST(p) (((p) >> 16) & 0xff)
#define DBC_DOOR_BELL_TARGET(p) (((p) & 0xff) << 8)
#define DBC_MAX_PACKET 1024
#define DBC_MAX_STRING_LENGTH 64
#define DBC_STRING_MANUFACTURER "Linux Foundation"
#define DBC_STRING_PRODUCT "Linux USB Debug Target"
#define DBC_STRING_SERIAL "0001"
#define DBC_CONTEXT_SIZE 64
/*
* Port status:
*/
#define DBC_PORTSC_CONN_STATUS BIT(0)
#define DBC_PORTSC_PORT_ENABLED BIT(1)
#define DBC_PORTSC_CONN_CHANGE BIT(17)
#define DBC_PORTSC_RESET_CHANGE BIT(21)
#define DBC_PORTSC_LINK_CHANGE BIT(22)
#define DBC_PORTSC_CONFIG_CHANGE BIT(23)
struct dbc_str_descs {
char string0[DBC_MAX_STRING_LENGTH];
char manufacturer[DBC_MAX_STRING_LENGTH];
char product[DBC_MAX_STRING_LENGTH];
char serial[DBC_MAX_STRING_LENGTH];
};
#define DBC_PROTOCOL 1 /* GNU Remote Debug Command */
#define DBC_VENDOR_ID 0x1d6b /* Linux Foundation 0x1d6b */
#define DBC_PRODUCT_ID 0x0010 /* device 0010 */
#define DBC_DEVICE_REV 0x0010 /* 0.10 */
enum dbc_state {
DS_DISABLED = 0,
DS_INITIALIZED,
DS_ENABLED,
DS_CONNECTED,
DS_CONFIGURED,
DS_STALLED,
};
struct dbc_request {
void *buf;
unsigned int length;
dma_addr_t dma;
void (*complete)(struct xhci_hcd *xhci,
struct dbc_request *req);
struct list_head list_pool;
int status;
unsigned int actual;
struct dbc_ep *dep;
struct list_head list_pending;
dma_addr_t trb_dma;
union xhci_trb *trb;
unsigned direction:1;
};
struct dbc_ep {
struct xhci_dbc *dbc;
struct list_head list_pending;
struct xhci_ring *ring;
unsigned direction:1;
};
#define DBC_QUEUE_SIZE 16
#define DBC_WRITE_BUF_SIZE 8192
/*
* Private structure for DbC hardware state:
*/
struct dbc_port {
struct tty_port port;
spinlock_t port_lock; /* port access */
struct list_head read_pool;
struct list_head read_queue;
unsigned int n_read;
struct tasklet_struct push;
struct list_head write_pool;
struct kfifo write_fifo;
bool registered;
struct dbc_ep *in;
struct dbc_ep *out;
};
struct xhci_dbc {
spinlock_t lock; /* device access */
struct xhci_hcd *xhci;
struct dbc_regs __iomem *regs;
struct xhci_ring *ring_evt;
struct xhci_ring *ring_in;
struct xhci_ring *ring_out;
struct xhci_erst erst;
struct xhci_container_ctx *ctx;
struct dbc_str_descs *string;
dma_addr_t string_dma;
size_t string_size;
enum dbc_state state;
struct delayed_work event_work;
unsigned resume_required:1;
struct dbc_ep eps[2];
struct dbc_port port;
};
#define dbc_bulkout_ctx(d) \
((struct xhci_ep_ctx *)((d)->ctx->bytes + DBC_CONTEXT_SIZE))
#define dbc_bulkin_ctx(d) \
((struct xhci_ep_ctx *)((d)->ctx->bytes + DBC_CONTEXT_SIZE * 2))
#define dbc_bulkout_enq(d) \
xhci_trb_virt_to_dma((d)->ring_out->enq_seg, (d)->ring_out->enqueue)
#define dbc_bulkin_enq(d) \
xhci_trb_virt_to_dma((d)->ring_in->enq_seg, (d)->ring_in->enqueue)
#define dbc_epctx_info2(t, p, b) \
cpu_to_le32(EP_TYPE(t) | MAX_PACKET(p) | MAX_BURST(b))
#define dbc_ep_dma_direction(d) \
((d)->direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE)
#define BULK_OUT 0
#define BULK_IN 1
#define EPID_OUT 2
#define EPID_IN 3
enum evtreturn {
EVT_ERR = -1,
EVT_DONE,
EVT_GSER,
EVT_DISC,
};
static inline struct dbc_ep *get_in_ep(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
return &dbc->eps[BULK_IN];
}
static inline struct dbc_ep *get_out_ep(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
return &dbc->eps[BULK_OUT];
}
#ifdef CONFIG_USB_XHCI_DBGCAP
int xhci_dbc_init(struct xhci_hcd *xhci);
void xhci_dbc_exit(struct xhci_hcd *xhci);
int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci);
void xhci_dbc_tty_unregister_driver(void);
int xhci_dbc_tty_register_device(struct xhci_hcd *xhci);
void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci);
struct dbc_request *dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags);
void dbc_free_request(struct dbc_ep *dep, struct dbc_request *req);
int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req, gfp_t gfp_flags);
#ifdef CONFIG_PM
int xhci_dbc_suspend(struct xhci_hcd *xhci);
int xhci_dbc_resume(struct xhci_hcd *xhci);
#endif /* CONFIG_PM */
#else
static inline int xhci_dbc_init(struct xhci_hcd *xhci)
{
return 0;
}
static inline void xhci_dbc_exit(struct xhci_hcd *xhci)
{
}
static inline int xhci_dbc_suspend(struct xhci_hcd *xhci)
{
return 0;
}
static inline int xhci_dbc_resume(struct xhci_hcd *xhci)
{
return 0;
}
#endif /* CONFIG_USB_XHCI_DBGCAP */
#endif /* __LINUX_XHCI_DBGCAP_H */

View file

@ -0,0 +1,497 @@
/**
* xhci-dbgtty.c - tty glue for xHCI debug capability
*
* Copyright (C) 2017 Intel Corporation
*
* Author: Lu Baolu <baolu.lu@linux.intel.com>
*/
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include "xhci.h"
#include "xhci-dbgcap.h"
static unsigned int
dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size)
{
unsigned int len;
len = kfifo_len(&port->write_fifo);
if (len < size)
size = len;
if (size != 0)
size = kfifo_out(&port->write_fifo, packet, size);
return size;
}
static int dbc_start_tx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
{
int len;
struct dbc_request *req;
int status = 0;
bool do_tty_wake = false;
struct list_head *pool = &port->write_pool;
while (!list_empty(pool)) {
req = list_entry(pool->next, struct dbc_request, list_pool);
len = dbc_send_packet(port, req->buf, DBC_MAX_PACKET);
if (len == 0)
break;
do_tty_wake = true;
req->length = len;
list_del(&req->list_pool);
spin_unlock(&port->port_lock);
status = dbc_ep_queue(port->out, req, GFP_ATOMIC);
spin_lock(&port->port_lock);
if (status) {
list_add(&req->list_pool, pool);
break;
}
}
if (do_tty_wake && port->port.tty)
tty_wakeup(port->port.tty);
return status;
}
static void dbc_start_rx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
{
struct dbc_request *req;
int status;
struct list_head *pool = &port->read_pool;
while (!list_empty(pool)) {
if (!port->port.tty)
break;
req = list_entry(pool->next, struct dbc_request, list_pool);
list_del(&req->list_pool);
req->length = DBC_MAX_PACKET;
spin_unlock(&port->port_lock);
status = dbc_ep_queue(port->in, req, GFP_ATOMIC);
spin_lock(&port->port_lock);
if (status) {
list_add(&req->list_pool, pool);
break;
}
}
}
static void
dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
{
struct xhci_dbc *dbc = xhci->dbc;
struct dbc_port *port = &dbc->port;
spin_lock(&port->port_lock);
list_add_tail(&req->list_pool, &port->read_queue);
tasklet_schedule(&port->push);
spin_unlock(&port->port_lock);
}
static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
{
struct xhci_dbc *dbc = xhci->dbc;
struct dbc_port *port = &dbc->port;
spin_lock(&port->port_lock);
list_add(&req->list_pool, &port->write_pool);
switch (req->status) {
case 0:
dbc_start_tx(port);
break;
case -ESHUTDOWN:
break;
default:
xhci_warn(xhci, "unexpected write complete status %d\n",
req->status);
break;
}
spin_unlock(&port->port_lock);
}
static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
{
kfree(req->buf);
dbc_free_request(dep, req);
}
static int
xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head,
void (*fn)(struct xhci_hcd *, struct dbc_request *))
{
int i;
struct dbc_request *req;
for (i = 0; i < DBC_QUEUE_SIZE; i++) {
req = dbc_alloc_request(dep, GFP_ATOMIC);
if (!req)
break;
req->length = DBC_MAX_PACKET;
req->buf = kmalloc(req->length, GFP_KERNEL);
if (!req->buf) {
xhci_dbc_free_req(dep, req);
break;
}
req->complete = fn;
list_add_tail(&req->list_pool, head);
}
return list_empty(head) ? -ENOMEM : 0;
}
static void
xhci_dbc_free_requests(struct dbc_ep *dep, struct list_head *head)
{
struct dbc_request *req;
while (!list_empty(head)) {
req = list_entry(head->next, struct dbc_request, list_pool);
list_del(&req->list_pool);
xhci_dbc_free_req(dep, req);
}
}
static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct dbc_port *port = driver->driver_state;
tty->driver_data = port;
return tty_port_install(&port->port, driver, tty);
}
static int dbc_tty_open(struct tty_struct *tty, struct file *file)
{
struct dbc_port *port = tty->driver_data;
return tty_port_open(&port->port, tty, file);
}
static void dbc_tty_close(struct tty_struct *tty, struct file *file)
{
struct dbc_port *port = tty->driver_data;
tty_port_close(&port->port, tty, file);
}
static int dbc_tty_write(struct tty_struct *tty,
const unsigned char *buf,
int count)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&port->port_lock, flags);
if (count)
count = kfifo_in(&port->write_fifo, buf, count);
dbc_start_tx(port);
spin_unlock_irqrestore(&port->port_lock, flags);
return count;
}
static int dbc_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
int status;
spin_lock_irqsave(&port->port_lock, flags);
status = kfifo_put(&port->write_fifo, ch);
spin_unlock_irqrestore(&port->port_lock, flags);
return status;
}
static void dbc_tty_flush_chars(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&port->port_lock, flags);
dbc_start_tx(port);
spin_unlock_irqrestore(&port->port_lock, flags);
}
static int dbc_tty_write_room(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
int room = 0;
spin_lock_irqsave(&port->port_lock, flags);
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->port_lock, flags);
return room;
}
static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
int chars = 0;
spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&port->port_lock, flags);
return chars;
}
static void dbc_tty_unthrottle(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&port->port_lock, flags);
tasklet_schedule(&port->push);
spin_unlock_irqrestore(&port->port_lock, flags);
}
static const struct tty_operations dbc_tty_ops = {
.install = dbc_tty_install,
.open = dbc_tty_open,
.close = dbc_tty_close,
.write = dbc_tty_write,
.put_char = dbc_tty_put_char,
.flush_chars = dbc_tty_flush_chars,
.write_room = dbc_tty_write_room,
.chars_in_buffer = dbc_tty_chars_in_buffer,
.unthrottle = dbc_tty_unthrottle,
};
static struct tty_driver *dbc_tty_driver;
int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci)
{
int status;
struct xhci_dbc *dbc = xhci->dbc;
dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(dbc_tty_driver)) {
status = PTR_ERR(dbc_tty_driver);
dbc_tty_driver = NULL;
return status;
}
dbc_tty_driver->driver_name = "dbc_serial";
dbc_tty_driver->name = "ttyDBC";
dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
dbc_tty_driver->init_termios = tty_std_termios;
dbc_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
dbc_tty_driver->init_termios.c_ispeed = 9600;
dbc_tty_driver->init_termios.c_ospeed = 9600;
dbc_tty_driver->driver_state = &dbc->port;
tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
status = tty_register_driver(dbc_tty_driver);
if (status) {
xhci_err(xhci,
"can't register dbc tty driver, err %d\n", status);
put_tty_driver(dbc_tty_driver);
dbc_tty_driver = NULL;
}
return status;
}
void xhci_dbc_tty_unregister_driver(void)
{
tty_unregister_driver(dbc_tty_driver);
put_tty_driver(dbc_tty_driver);
dbc_tty_driver = NULL;
}
static void dbc_rx_push(unsigned long _port)
{
struct dbc_request *req;
struct tty_struct *tty;
bool do_push = false;
bool disconnect = false;
struct dbc_port *port = (void *)_port;
struct list_head *queue = &port->read_queue;
spin_lock_irq(&port->port_lock);
tty = port->port.tty;
while (!list_empty(queue)) {
req = list_first_entry(queue, struct dbc_request, list_pool);
if (tty && tty_throttled(tty))
break;
switch (req->status) {
case 0:
break;
case -ESHUTDOWN:
disconnect = true;
break;
default:
pr_warn("ttyDBC0: unexpected RX status %d\n",
req->status);
break;
}
if (req->actual) {
char *packet = req->buf;
unsigned int n, size = req->actual;
int count;
n = port->n_read;
if (n) {
packet += n;
size -= n;
}
count = tty_insert_flip_string(&port->port, packet,
size);
if (count)
do_push = true;
if (count != size) {
port->n_read += count;
break;
}
port->n_read = 0;
}
list_move(&req->list_pool, &port->read_pool);
}
if (do_push)
tty_flip_buffer_push(&port->port);
if (!list_empty(queue) && tty) {
if (!tty_throttled(tty)) {
if (do_push)
tasklet_schedule(&port->push);
else
pr_warn("ttyDBC0: RX not scheduled?\n");
}
}
if (!disconnect)
dbc_start_rx(port);
spin_unlock_irq(&port->port_lock);
}
static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
{
struct dbc_port *port = container_of(_port, struct dbc_port, port);
spin_lock_irq(&port->port_lock);
dbc_start_rx(port);
spin_unlock_irq(&port->port_lock);
return 0;
}
static const struct tty_port_operations dbc_port_ops = {
.activate = dbc_port_activate,
};
static void
xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port)
{
tty_port_init(&port->port);
spin_lock_init(&port->port_lock);
tasklet_init(&port->push, dbc_rx_push, (unsigned long)port);
INIT_LIST_HEAD(&port->read_pool);
INIT_LIST_HEAD(&port->read_queue);
INIT_LIST_HEAD(&port->write_pool);
port->in = get_in_ep(xhci);
port->out = get_out_ep(xhci);
port->port.ops = &dbc_port_ops;
port->n_read = 0;
}
static void
xhci_dbc_tty_exit_port(struct dbc_port *port)
{
tasklet_kill(&port->push);
tty_port_destroy(&port->port);
}
int xhci_dbc_tty_register_device(struct xhci_hcd *xhci)
{
int ret;
struct device *tty_dev;
struct xhci_dbc *dbc = xhci->dbc;
struct dbc_port *port = &dbc->port;
xhci_dbc_tty_init_port(xhci, port);
tty_dev = tty_port_register_device(&port->port,
dbc_tty_driver, 0, NULL);
ret = IS_ERR_OR_NULL(tty_dev);
if (ret)
goto register_fail;
ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
if (ret)
goto buf_alloc_fail;
ret = xhci_dbc_alloc_requests(port->in, &port->read_pool,
dbc_read_complete);
if (ret)
goto request_fail;
ret = xhci_dbc_alloc_requests(port->out, &port->write_pool,
dbc_write_complete);
if (ret)
goto request_fail;
port->registered = true;
return 0;
request_fail:
xhci_dbc_free_requests(port->in, &port->read_pool);
xhci_dbc_free_requests(port->out, &port->write_pool);
kfifo_free(&port->write_fifo);
buf_alloc_fail:
tty_unregister_device(dbc_tty_driver, 0);
register_fail:
xhci_dbc_tty_exit_port(port);
xhci_err(xhci, "can't register tty port, err %d\n", ret);
return ret;
}
void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci)
{
struct xhci_dbc *dbc = xhci->dbc;
struct dbc_port *port = &dbc->port;
tty_unregister_device(dbc_tty_driver, 0);
xhci_dbc_tty_exit_port(port);
port->registered = false;
kfifo_free(&port->write_fifo);
xhci_dbc_free_requests(get_out_ep(xhci), &port->read_pool);
xhci_dbc_free_requests(get_out_ep(xhci), &port->read_queue);
xhci_dbc_free_requests(get_in_ep(xhci), &port->write_pool);
}

View file

@ -388,7 +388,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
trace_xhci_stop_device(virt_dev);
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
cmd = xhci_alloc_command(xhci, true, GFP_NOIO);
if (!cmd)
return -ENOMEM;
@ -404,8 +404,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_RUNNING)
continue;
command = xhci_alloc_command(xhci, false, false,
GFP_NOWAIT);
command = xhci_alloc_command(xhci, false, GFP_NOWAIT);
if (!command) {
spin_unlock_irqrestore(&xhci->lock, flags);
ret = -ENOMEM;
@ -1077,6 +1076,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
retval = -ENODEV;
break;
}
trace_xhci_get_port_status(wIndex, temp);
status = xhci_get_port_status(hcd, bus_state, port_array,
wIndex, temp, flags);
if (status == 0xffffffff)
@ -1443,6 +1443,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
retval = -ENODEV;
break;
}
trace_xhci_hub_status_data(i, temp);
if ((temp & mask) != 0 ||
(bus_state->port_c_suspend & 1 << i) ||
(bus_state->resume_done[i] && time_after_eq(

View file

@ -357,7 +357,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
* Set the end flag and the cycle toggle bit on the last segment.
* See section 4.9.1 and figures 15 and 16.
*/
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
unsigned int num_segs, unsigned int cycle_state,
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
{
@ -454,7 +454,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
return 0;
}
static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
int type, gfp_t flags)
{
struct xhci_container_ctx *ctx;
@ -479,7 +479,7 @@ static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci
return ctx;
}
static void xhci_free_container_ctx(struct xhci_hcd *xhci,
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx)
{
if (!ctx)
@ -650,7 +650,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
/* Allocate everything needed to free the stream rings later */
stream_info->free_streams_command =
xhci_alloc_command(xhci, true, true, mem_flags);
xhci_alloc_command_with_ctx(xhci, true, mem_flags);
if (!stream_info->free_streams_command)
goto cleanup_ctx;
@ -1715,8 +1715,7 @@ static void scratchpad_free(struct xhci_hcd *xhci)
}
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_in_ctx, bool allocate_completion,
gfp_t mem_flags)
bool allocate_completion, gfp_t mem_flags)
{
struct xhci_command *command;
@ -1724,21 +1723,10 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
if (!command)
return NULL;
if (allocate_in_ctx) {
command->in_ctx =
xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT,
mem_flags);
if (!command->in_ctx) {
kfree(command);
return NULL;
}
}
if (allocate_completion) {
command->completion =
kzalloc(sizeof(struct completion), mem_flags);
if (!command->completion) {
xhci_free_container_ctx(xhci, command->in_ctx);
kfree(command);
return NULL;
}
@ -1750,6 +1738,25 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
return command;
}
struct xhci_command *xhci_alloc_command_with_ctx(struct xhci_hcd *xhci,
bool allocate_completion, gfp_t mem_flags)
{
struct xhci_command *command;
command = xhci_alloc_command(xhci, allocate_completion, mem_flags);
if (!command)
return NULL;
command->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT,
mem_flags);
if (!command->in_ctx) {
kfree(command->completion);
kfree(command);
return NULL;
}
return command;
}
void xhci_urb_free_priv(struct urb_priv *urb_priv)
{
kfree(urb_priv);
@ -1764,21 +1771,58 @@ void xhci_free_command(struct xhci_hcd *xhci,
kfree(command);
}
int xhci_alloc_erst(struct xhci_hcd *xhci,
struct xhci_ring *evt_ring,
struct xhci_erst *erst,
gfp_t flags)
{
size_t size;
unsigned int val;
struct xhci_segment *seg;
struct xhci_erst_entry *entry;
size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs;
erst->entries = dma_zalloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, &erst->erst_dma_addr, flags);
if (!erst->entries)
return -ENOMEM;
erst->num_entries = evt_ring->num_segs;
seg = evt_ring->first_seg;
for (val = 0; val < evt_ring->num_segs; val++) {
entry = &erst->entries[val];
entry->seg_addr = cpu_to_le64(seg->dma);
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
seg = seg->next;
}
return 0;
}
void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
{
size_t size;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
if (erst->entries)
dma_free_coherent(dev, size,
erst->entries,
erst->erst_dma_addr);
erst->entries = NULL;
}
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
int size;
int i, j, num_ports;
cancel_delayed_work_sync(&xhci->cmd_timer);
/* Free the Event Ring Segment Table and the actual Event Ring */
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
dma_free_coherent(dev, size,
xhci->erst.entries, xhci->erst.erst_dma_addr);
xhci->erst.entries = NULL;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST");
xhci_free_erst(xhci, &xhci->erst);
if (xhci->event_ring)
xhci_ring_free(xhci, xhci->event_ring);
xhci->event_ring = NULL;
@ -2315,9 +2359,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
unsigned int val, val2;
u64 val_64;
struct xhci_segment *seg;
u32 page_size, temp;
int i;
u32 page_size, temp;
int i, ret;
INIT_LIST_HEAD(&xhci->cmd_list);
@ -2421,9 +2464,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Setting command ring address to 0x%016llx", val_64);
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
xhci->lpm_command = xhci_alloc_command_with_ctx(xhci, true, flags);
if (!xhci->lpm_command)
goto fail;
@ -2439,8 +2481,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
"// Doorbell array is located at offset 0x%x"
" from cap regs base addr", val);
xhci->dba = (void __iomem *) xhci->cap_regs + val;
xhci_dbg_regs(xhci);
xhci_print_run_regs(xhci);
/* Set ir_set to interrupt register set 0 */
xhci->ir_set = &xhci->run_regs->ir_set[0];
@ -2456,32 +2496,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
if (xhci_check_trb_in_td_math(xhci) < 0)
goto fail;
xhci->erst.entries = dma_alloc_coherent(dev,
sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
flags);
if (!xhci->erst.entries)
ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
if (ret)
goto fail;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Allocated event ring segment table at 0x%llx",
(unsigned long long)dma);
memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
xhci->erst.num_entries = ERST_NUM_SEGS;
xhci->erst.erst_dma_addr = dma;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx",
xhci->erst.num_entries,
xhci->erst.entries,
(unsigned long long)xhci->erst.erst_dma_addr);
/* set ring base address and size for each segment table entry */
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
entry->seg_addr = cpu_to_le64(seg->dma);
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
seg = seg->next;
}
/* set ERST count with the number of entries in the segment table */
val = readl(&xhci->ir_set->erst_size);
@ -2507,7 +2524,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_set_hc_event_deq(xhci);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Wrote ERST address to ir_set 0.");
xhci_print_ir_set(xhci, 0);
/*
* XXX: Might need to set the Interrupter Moderation Register to

View file

@ -57,26 +57,21 @@
/* u2_phy_pll register */
#define CTRL_U2_FORCE_PLL_STB BIT(28)
#define PERI_WK_CTRL0 0x400
#define UWK_CTR0_0P_LS_PE BIT(8) /* posedge */
#define UWK_CTR0_0P_LS_NE BIT(7) /* negedge for 0p linestate*/
#define UWK_CTL1_1P_LS_C(x) (((x) & 0xf) << 1)
#define UWK_CTL1_1P_LS_E BIT(0)
/* usb remote wakeup registers in syscon */
/* mt8173 etc */
#define PERI_WK_CTRL1 0x4
#define WC1_IS_C(x) (((x) & 0xf) << 26) /* cycle debounce */
#define WC1_IS_EN BIT(25)
#define WC1_IS_P BIT(6) /* polarity for ip sleep */
#define PERI_WK_CTRL1 0x404
#define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26)
#define UWK_CTL1_IS_E BIT(25)
#define UWK_CTL1_0P_LS_C(x) (((x) & 0xf) << 21)
#define UWK_CTL1_0P_LS_E BIT(20)
#define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */
#define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */
#define UWK_CTL1_IDDIG_P BIT(9) /* polarity */
#define UWK_CTL1_0P_LS_P BIT(7)
#define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */
/* mt2712 etc */
#define PERI_SSUSB_SPM_CTRL 0x0
#define SSC_IP_SLEEP_EN BIT(4)
#define SSC_SPM_INT_EN BIT(1)
enum ssusb_wakeup_src {
SSUSB_WK_IP_SLEEP = 1,
SSUSB_WK_LINE_STATE = 2,
enum ssusb_uwk_vers {
SSUSB_UWK_V1 = 1,
SSUSB_UWK_V2,
};
static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
@ -296,112 +291,58 @@ static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk)
}
/* only clocks can be turn off for ip-sleep wakeup mode */
static void usb_wakeup_ip_sleep_en(struct xhci_hcd_mtk *mtk)
static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable)
{
u32 tmp;
struct regmap *pericfg = mtk->pericfg;
u32 reg, msk, val;
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_IS_P;
tmp &= ~(UWK_CTL1_IS_C(0xf));
tmp |= UWK_CTL1_IS_C(0x8);
regmap_write(pericfg, PERI_WK_CTRL1, tmp);
regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
dev_dbg(mtk->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
__func__, tmp);
}
static void usb_wakeup_ip_sleep_dis(struct xhci_hcd_mtk *mtk)
{
u32 tmp;
regmap_read(mtk->pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_IS_E;
regmap_write(mtk->pericfg, PERI_WK_CTRL1, tmp);
}
/*
* for line-state wakeup mode, phy's power should not power-down
* and only support cable plug in/out
*/
static void usb_wakeup_line_state_en(struct xhci_hcd_mtk *mtk)
{
u32 tmp;
struct regmap *pericfg = mtk->pericfg;
/* line-state of u2-port0 */
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_0P_LS_P;
tmp &= ~(UWK_CTL1_0P_LS_C(0xf));
tmp |= UWK_CTL1_0P_LS_C(0x8);
regmap_write(pericfg, PERI_WK_CTRL1, tmp);
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_0P_LS_E);
/* line-state of u2-port1 */
regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
tmp &= ~(UWK_CTL1_1P_LS_C(0xf));
tmp |= UWK_CTL1_1P_LS_C(0x8);
regmap_write(pericfg, PERI_WK_CTRL0, tmp);
regmap_write(pericfg, PERI_WK_CTRL0, tmp | UWK_CTL1_1P_LS_E);
}
static void usb_wakeup_line_state_dis(struct xhci_hcd_mtk *mtk)
{
u32 tmp;
struct regmap *pericfg = mtk->pericfg;
/* line-state of u2-port0 */
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_0P_LS_E;
regmap_write(pericfg, PERI_WK_CTRL1, tmp);
/* line-state of u2-port1 */
regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
tmp &= ~UWK_CTL1_1P_LS_E;
regmap_write(pericfg, PERI_WK_CTRL0, tmp);
}
static void usb_wakeup_enable(struct xhci_hcd_mtk *mtk)
{
if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
usb_wakeup_ip_sleep_en(mtk);
else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
usb_wakeup_line_state_en(mtk);
}
static void usb_wakeup_disable(struct xhci_hcd_mtk *mtk)
{
if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
usb_wakeup_ip_sleep_dis(mtk);
else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
usb_wakeup_line_state_dis(mtk);
switch (mtk->uwk_vers) {
case SSUSB_UWK_V1:
reg = mtk->uwk_reg_base + PERI_WK_CTRL1;
msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P;
val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0;
break;
case SSUSB_UWK_V2:
reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
val = enable ? msk : 0;
break;
default:
return;
}
regmap_update_bits(mtk->uwk, reg, msk, val);
}
static int usb_wakeup_of_property_parse(struct xhci_hcd_mtk *mtk,
struct device_node *dn)
{
struct device *dev = mtk->dev;
struct of_phandle_args args;
int ret;
/*
* wakeup function is optional, so it is not an error if this property
* does not exist, and in such case, no need to get relative
* properties anymore.
*/
of_property_read_u32(dn, "mediatek,wakeup-src", &mtk->wakeup_src);
if (!mtk->wakeup_src)
/* Wakeup function is optional */
mtk->uwk_en = of_property_read_bool(dn, "wakeup-source");
if (!mtk->uwk_en)
return 0;
mtk->pericfg = syscon_regmap_lookup_by_phandle(dn,
"mediatek,syscon-wakeup");
if (IS_ERR(mtk->pericfg)) {
dev_err(dev, "fail to get pericfg regs\n");
return PTR_ERR(mtk->pericfg);
}
ret = of_parse_phandle_with_fixed_args(dn,
"mediatek,syscon-wakeup", 2, 0, &args);
if (ret)
return ret;
return 0;
mtk->uwk_reg_base = args.args[0];
mtk->uwk_vers = args.args[1];
mtk->uwk = syscon_node_to_regmap(args.np);
of_node_put(args.np);
dev_info(mtk->dev, "uwk - reg:0x%x, version:%d\n",
mtk->uwk_reg_base, mtk->uwk_vers);
return PTR_ERR_OR_ZERO(mtk->uwk);
}
static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
{
if (mtk->uwk_en)
usb_wakeup_ip_sleep_set(mtk, enable);
}
static int xhci_mtk_setup(struct usb_hcd *hcd);
@ -583,8 +524,10 @@ static int xhci_mtk_probe(struct platform_device *pdev)
&mtk->u3p_dis_msk);
ret = usb_wakeup_of_property_parse(mtk, node);
if (ret)
if (ret) {
dev_err(dev, "failed to parse uwk property\n");
return ret;
}
mtk->num_phys = of_count_phandle_with_args(node,
"phys", "#phy-cells");
@ -674,6 +617,15 @@ static int xhci_mtk_probe(struct platform_device *pdev)
xhci = hcd_to_xhci(hcd);
xhci->main_hcd = hcd;
/*
* imod_interval is the interrupt moderation value in nanoseconds.
* The increment interval is 8 times as much as that defined in
* the xHCI spec on MTK's controller.
*/
xhci->imod_interval = 5000;
device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
dev_name(dev), hcd);
if (!xhci->shared_hcd) {
@ -768,7 +720,7 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
xhci_mtk_host_disable(mtk);
xhci_mtk_phy_power_off(mtk);
xhci_mtk_clks_disable(mtk);
usb_wakeup_enable(mtk);
usb_wakeup_set(mtk, true);
return 0;
}
@ -778,7 +730,7 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
struct usb_hcd *hcd = mtk->hcd;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
usb_wakeup_disable(mtk);
usb_wakeup_set(mtk, false);
xhci_mtk_clks_enable(mtk);
xhci_mtk_phy_power_on(mtk);
xhci_mtk_host_enable(mtk);

View file

@ -122,8 +122,12 @@ struct xhci_hcd_mtk {
struct regmap *pericfg;
struct phy **phys;
int num_phys;
int wakeup_src;
bool lpm_support;
/* usb remote wakeup */
bool uwk_en;
struct regmap *uwk;
u32 uwk_reg_base;
u32 uwk_vers;
};
static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)

View file

@ -237,6 +237,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
if (!xhci->sbrn)
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
/* imod_interval is the interrupt moderation value in nanoseconds. */
xhci->imod_interval = 40000;
retval = xhci_gen_setup(hcd, xhci_pci_quirks);
if (retval)
return retval;

View file

@ -269,6 +269,11 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped"))
xhci->quirks |= XHCI_BROKEN_PORT_PED;
/* imod_interval is the interrupt moderation value in nanoseconds. */
xhci->imod_interval = 40000;
device_property_read_u32(sysdev, "imod-interval-ns",
&xhci->imod_interval);
hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
if (IS_ERR(hcd->usb_phy)) {
ret = PTR_ERR(hcd->usb_phy);

View file

@ -153,7 +153,7 @@ static void next_trb(struct xhci_hcd *xhci,
* See Cycle bit rules. SW is the consumer for the event ring only.
* Don't make a ring full of link TRBs. That would be dumb and this would loop.
*/
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
/* event ring doesn't have link trbs, check for last trb */
if (ring->type == TYPE_EVENT) {
@ -1141,7 +1141,7 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
struct xhci_command *command;
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command)
return;
@ -1821,7 +1821,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
struct xhci_command *command;
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command)
return;
@ -1878,12 +1878,10 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_ring *ep_ring, int *status)
{
struct urb_priv *urb_priv;
struct urb *urb = NULL;
/* Clean up the endpoint's TD list */
urb = td->urb;
urb_priv = urb->hcpriv;
/* if a bounce buffer was used to align this td then unmap it */
xhci_unmap_td_bounce_buffer(xhci, ep_ring, td);
@ -1994,7 +1992,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_virt_ep *ep, int *status)
{
struct xhci_virt_device *xdev;
struct xhci_ring *ep_ring;
unsigned int slot_id;
int ep_index;
struct xhci_ep_ctx *ep_ctx;
@ -2006,7 +2003,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
requested = td->urb->transfer_buffer_length;
@ -2965,7 +2961,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
return 0;
}
static unsigned int count_trbs(u64 addr, u64 len)
unsigned int count_trbs(u64 addr, u64 len)
{
unsigned int num_trbs;
@ -4044,7 +4040,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
}
/* This function gets called from contexts where it cannot sleep */
cmd = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
cmd = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!cmd)
return;

View file

@ -23,6 +23,7 @@
#include <linux/tracepoint.h>
#include "xhci.h"
#include "xhci-dbgcap.h"
#define XHCI_MSG_MAX 500
@ -155,6 +156,21 @@ DEFINE_EVENT(xhci_log_trb, xhci_queue_trb,
TP_ARGS(ring, trb)
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_event,
TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
TP_ARGS(ring, trb)
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_transfer,
TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
TP_ARGS(ring, trb)
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_gadget_ep_queue,
TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
TP_ARGS(ring, trb)
);
DECLARE_EVENT_CLASS(xhci_log_virt_dev,
TP_PROTO(struct xhci_virt_device *vdev),
TP_ARGS(vdev),
@ -478,6 +494,59 @@ DEFINE_EVENT(xhci_log_portsc, xhci_handle_port_status,
TP_ARGS(portnum, portsc)
);
DEFINE_EVENT(xhci_log_portsc, xhci_get_port_status,
TP_PROTO(u32 portnum, u32 portsc),
TP_ARGS(portnum, portsc)
);
DEFINE_EVENT(xhci_log_portsc, xhci_hub_status_data,
TP_PROTO(u32 portnum, u32 portsc),
TP_ARGS(portnum, portsc)
);
DECLARE_EVENT_CLASS(xhci_dbc_log_request,
TP_PROTO(struct dbc_request *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field(struct dbc_request *, req)
__field(bool, dir)
__field(unsigned int, actual)
__field(unsigned int, length)
__field(int, status)
),
TP_fast_assign(
__entry->req = req;
__entry->dir = req->direction;
__entry->actual = req->actual;
__entry->length = req->length;
__entry->status = req->status;
),
TP_printk("%s: req %p length %u/%u ==> %d",
__entry->dir ? "bulk-in" : "bulk-out",
__entry->req, __entry->actual,
__entry->length, __entry->status
)
);
DEFINE_EVENT(xhci_dbc_log_request, xhci_dbc_alloc_request,
TP_PROTO(struct dbc_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(xhci_dbc_log_request, xhci_dbc_free_request,
TP_PROTO(struct dbc_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(xhci_dbc_log_request, xhci_dbc_queue_request,
TP_PROTO(struct dbc_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(xhci_dbc_log_request, xhci_dbc_giveback_request,
TP_PROTO(struct dbc_request *req),
TP_ARGS(req)
);
#endif /* __XHCI_TRACE_H */
/* this part must be outside header guard */

View file

@ -21,6 +21,7 @@
#include "xhci-trace.h"
#include "xhci-mtk.h"
#include "xhci-debugfs.h"
#include "xhci-dbgcap.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@ -573,10 +574,6 @@ int xhci_run(struct usb_hcd *hcd)
if (ret)
return ret;
xhci_dbg_cmd_ptrs(xhci);
xhci_dbg(xhci, "ERST memory map follows:\n");
xhci_dbg_erst(xhci, &xhci->erst);
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
temp_64 &= ~ERST_PTR_MASK;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@ -586,11 +583,7 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
/*
* the increment interval is 8 times as much as that defined
* in xHCI spec on MTK's controller
*/
temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160);
temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
@ -605,12 +598,11 @@ int xhci_run(struct usb_hcd *hcd)
"// Enabling event ring interrupter %p by writing 0x%x to irq_pending",
xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0);
if (xhci->quirks & XHCI_NEC_HOST) {
struct xhci_command *command;
command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
command = xhci_alloc_command(xhci, false, GFP_KERNEL);
if (!command)
return -ENOMEM;
@ -622,6 +614,8 @@ int xhci_run(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Finished xhci_run for USB2 roothub");
xhci_dbc_init(xhci);
xhci_debugfs_init(xhci);
return 0;
@ -654,6 +648,8 @@ static void xhci_stop(struct usb_hcd *hcd)
xhci_debugfs_exit(xhci);
xhci_dbc_exit(xhci);
spin_lock_irq(&xhci->lock);
xhci->xhc_state |= XHCI_STATE_HALTED;
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
@ -681,7 +677,6 @@ static void xhci_stop(struct usb_hcd *hcd)
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
temp = readl(&xhci->ir_set->irq_pending);
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
xhci_mem_cleanup(xhci);
@ -870,6 +865,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
xhci->shared_hcd->state != HC_STATE_SUSPENDED)
return -EINVAL;
xhci_dbc_suspend(xhci);
/* Clear root port wake on bits if wakeup not allowed. */
if (!do_wakeup)
xhci_disable_port_wake_on_bits(xhci);
@ -1014,7 +1011,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
temp = readl(&xhci->ir_set->irq_pending);
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0);
xhci_dbg(xhci, "cleaning up memory\n");
xhci_mem_cleanup(xhci);
@ -1065,6 +1061,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
spin_unlock_irq(&xhci->lock);
xhci_dbc_resume(xhci);
done:
if (retval == 0) {
/* Resume root hubs only when have pending events. */
@ -1243,7 +1241,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
* changes max packet sizes.
*/
command = xhci_alloc_command(xhci, false, true, GFP_KERNEL);
command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command)
return -ENOMEM;
@ -1498,7 +1496,7 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
* the first cancellation to be handled.
*/
if (!(ep->ep_state & EP_STOP_CMD_PENDING)) {
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command) {
ret = -ENOMEM;
goto done;
@ -2683,7 +2681,7 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
virt_dev = xhci->devs[udev->slot_id];
command = xhci_alloc_command(xhci, false, true, GFP_KERNEL);
command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command)
return -ENOMEM;
@ -2838,12 +2836,10 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index,
unsigned int stream_id, struct xhci_td *td)
{
struct xhci_dequeue_state deq_state;
struct xhci_virt_ep *ep;
struct usb_device *udev = td->urb->dev;
xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
"Cleaning up stalled endpoint ring");
ep = &xhci->devs[udev->slot_id]->eps[ep_index];
/* We need to move the HW's dequeue pointer past this TD,
* or it will attempt to resend it on the next doorbell ring.
*/
@ -3092,7 +3088,7 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
return -ENOSYS;
}
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
config_cmd = xhci_alloc_command_with_ctx(xhci, true, mem_flags);
if (!config_cmd)
return -ENOMEM;
@ -3363,7 +3359,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
unsigned int slot_id;
struct xhci_virt_device *virt_dev;
struct xhci_command *reset_device_cmd;
int last_freed_endpoint;
struct xhci_slot_ctx *slot_ctx;
int old_active_eps = 0;
@ -3416,7 +3411,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
* reset as part of error handling, so use GFP_NOIO instead of
* GFP_KERNEL.
*/
reset_device_cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
reset_device_cmd = xhci_alloc_command(xhci, true, GFP_NOIO);
if (!reset_device_cmd) {
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
return -ENOMEM;
@ -3478,7 +3473,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
/* Everything but endpoint 0 is disabled, so free the rings. */
last_freed_endpoint = 1;
for (i = 1; i < 31; i++) {
struct xhci_virt_ep *ep = &virt_dev->eps[i];
@ -3493,7 +3487,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
if (ep->ring) {
xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
xhci_free_endpoint_ring(xhci, virt_dev, i);
last_freed_endpoint = i;
}
if (!list_empty(&virt_dev->eps[i].bw_endpoint_list))
xhci_drop_ep_from_interval_table(xhci,
@ -3566,7 +3559,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
u32 state;
int ret = 0;
command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
command = xhci_alloc_command(xhci, false, GFP_KERNEL);
if (!command)
return -ENOMEM;
@ -3628,7 +3621,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
int ret, slot_id;
struct xhci_command *command;
command = xhci_alloc_command(xhci, false, true, GFP_KERNEL);
command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command)
return 0;
@ -3761,7 +3754,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
}
}
command = xhci_alloc_command(xhci, false, true, GFP_KERNEL);
command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command) {
ret = -ENOMEM;
goto out;
@ -4680,7 +4673,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
return -EINVAL;
}
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
config_cmd = xhci_alloc_command_with_ctx(xhci, true, mem_flags);
if (!config_cmd)
return -ENOMEM;
@ -4828,7 +4821,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
if (xhci->hci_version > 0x100)
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
xhci_print_registers(xhci);
xhci->quirks |= quirks;

View file

@ -1717,6 +1717,8 @@ struct xhci_hcd {
u8 max_interrupters;
u8 max_ports;
u8 isoc_threshold;
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
int event_ring_max;
/* 4KB min, 128MB max */
int page_size;
@ -1856,6 +1858,7 @@ struct xhci_hcd {
struct dentry *debugfs_slots;
struct list_head regset_list;
void *dbc;
/* platform-specific data -- must come last */
unsigned long priv[0] __aligned(sizeof(s64));
};
@ -1924,12 +1927,6 @@ static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
}
/* xHCI debugging */
void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num);
void xhci_print_registers(struct xhci_hcd *xhci);
void xhci_dbg_regs(struct xhci_hcd *xhci);
void xhci_print_run_regs(struct xhci_hcd *xhci);
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
char *xhci_get_slot_state(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx);
void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
@ -1965,9 +1962,17 @@ void xhci_slot_copy(struct xhci_hcd *xhci,
int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
unsigned int num_segs, unsigned int cycle_state,
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags);
unsigned int num_trbs, gfp_t flags);
int xhci_alloc_erst(struct xhci_hcd *xhci,
struct xhci_ring *evt_ring,
struct xhci_erst *erst,
gfp_t flags);
void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index);
@ -1992,11 +1997,16 @@ struct xhci_ring *xhci_stream_id_to_ring(
unsigned int ep_index,
unsigned int stream_id);
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_in_ctx, bool allocate_completion,
gfp_t mem_flags);
bool allocate_completion, gfp_t mem_flags);
struct xhci_command *xhci_alloc_command_with_ctx(struct xhci_hcd *xhci,
bool allocate_completion, gfp_t mem_flags);
void xhci_urb_free_priv(struct urb_priv *urb_priv);
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command);
struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
int type, gfp_t flags);
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx);
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
@ -2070,6 +2080,8 @@ void xhci_handle_command_timeout(struct work_struct *work);
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id);
void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,

View file

@ -183,10 +183,10 @@ static int chaoskey_probe(struct usb_interface *interface,
dev->in_ep = in_ep;
if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
dev->reads_started = 1;
dev->reads_started = true;
dev->size = size;
dev->present = 1;
dev->present = true;
init_waitqueue_head(&dev->wait_q);
@ -239,7 +239,7 @@ static void chaoskey_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
mutex_lock(&dev->lock);
dev->present = 0;
dev->present = false;
usb_poison_urb(dev->urb);
if (!dev->open) {

View file

@ -144,7 +144,7 @@ error:
}
/* attribute callback handler (write) */
static ssize_t set_port0_handler(struct device *dev,
static ssize_t port0_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@ -152,7 +152,7 @@ static ssize_t set_port0_handler(struct device *dev,
}
/* attribute callback handler (write) */
static ssize_t set_port1_handler(struct device *dev,
static ssize_t port1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@ -178,22 +178,22 @@ static ssize_t read_port(struct device *dev, struct device_attribute *attr,
}
/* attribute callback handler (read) */
static ssize_t get_port0_handler(struct device *dev,
static ssize_t port0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0);
}
/* attribute callback handler (read) */
static ssize_t get_port1_handler(struct device *dev,
static ssize_t port1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
}
static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler);
static DEVICE_ATTR_RW(port0);
static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler);
static DEVICE_ATTR_RW(port1);
static int cypress_probe(struct usb_interface *interface,

View file

@ -78,7 +78,7 @@ static int vendor_command(struct usb_device *dev, unsigned char request,
#define BRIGHTNESS 0x2c /* RAM location for brightness value */
#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */
static ssize_t show_brightness(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
@ -86,7 +86,7 @@ static ssize_t show_brightness(struct device *dev, struct device_attribute *attr
return sprintf(buf, "%i", cytherm->brightness);
}
static ssize_t set_brightness(struct device *dev, struct device_attribute *attr, const char *buf,
static ssize_t brightness_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -121,15 +121,13 @@ static ssize_t set_brightness(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP,
show_brightness, set_brightness);
static DEVICE_ATTR_RW(brightness);
#define TEMP 0x33 /* RAM location for temperature */
#define SIGN 0x34 /* RAM location for temperature sign */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -161,19 +159,12 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char
return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
5*(temp - ((temp >> 1) << 1)));
}
static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
return count;
}
static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
static DEVICE_ATTR_RO(temp);
#define BUTTON 0x7a
static ssize_t show_button(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t button_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -200,17 +191,10 @@ static ssize_t show_button(struct device *dev, struct device_attribute *attr, ch
else
return sprintf(buf, "0");
}
static DEVICE_ATTR_RO(button);
static ssize_t set_button(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
return count;
}
static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
static ssize_t show_port0(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t port0_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
@ -234,7 +218,7 @@ static ssize_t show_port0(struct device *dev, struct device_attribute *attr, cha
}
static ssize_t set_port0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
static ssize_t port0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
@ -263,10 +247,9 @@ static ssize_t set_port0(struct device *dev, struct device_attribute *attr, cons
return count;
}
static DEVICE_ATTR_RW(port0);
static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
static ssize_t show_port1(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t port1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
@ -290,7 +273,7 @@ static ssize_t show_port1(struct device *dev, struct device_attribute *attr, cha
}
static ssize_t set_port1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
static ssize_t port1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
@ -319,9 +302,7 @@ static ssize_t set_port1(struct device *dev, struct device_attribute *attr, cons
return count;
}
static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
static DEVICE_ATTR_RW(port1);
static int cytherm_probe(struct usb_interface *interface,

View file

@ -30,7 +30,7 @@ struct trancevibrator {
unsigned int speed;
};
static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -39,7 +39,7 @@ static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", tv->speed);
}
static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -70,7 +70,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed);
static DEVICE_ATTR_RW(speed);
static int tv_probe(struct usb_interface *interface,
const struct usb_device_id *id)

View file

@ -165,7 +165,7 @@ static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
}
#define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \
static ssize_t show_attr_##name(struct device *dev, \
static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@ -174,7 +174,7 @@ static ssize_t show_attr_##name(struct device *dev, \
return sprintf(buf, "%u\n", mydev->name); \
} \
\
static ssize_t set_attr_##name(struct device *dev, \
static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@ -185,9 +185,9 @@ static ssize_t set_attr_##name(struct device *dev, \
\
return count; \
} \
static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name);
static DEVICE_ATTR_RW(name);
static ssize_t show_attr_text(struct device *dev,
static ssize_t text_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -196,7 +196,7 @@ static ssize_t show_attr_text(struct device *dev,
return snprintf(buf, mydev->textlength, "%s\n", mydev->text);
}
static ssize_t set_attr_text(struct device *dev,
static ssize_t text_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -216,9 +216,9 @@ static ssize_t set_attr_text(struct device *dev,
return count;
}
static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text);
static DEVICE_ATTR_RW(text);
static ssize_t show_attr_decimals(struct device *dev,
static ssize_t decimals_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -240,7 +240,7 @@ static ssize_t show_attr_decimals(struct device *dev,
return sizeof(mydev->decimals) + 1;
}
static ssize_t set_attr_decimals(struct device *dev,
static ssize_t decimals_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -265,9 +265,9 @@ static ssize_t set_attr_decimals(struct device *dev,
return count;
}
static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals);
static DEVICE_ATTR_RW(decimals);
static ssize_t show_attr_textmode(struct device *dev,
static ssize_t textmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -293,7 +293,7 @@ static ssize_t show_attr_textmode(struct device *dev,
return strlen(buf);
}
static ssize_t set_attr_textmode(struct device *dev,
static ssize_t textmode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
@ -309,7 +309,7 @@ static ssize_t set_attr_textmode(struct device *dev,
return count;
}
static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
static DEVICE_ATTR_RW(textmode);
MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);

View file

@ -1710,6 +1710,35 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
return 0;
}
static int test_toggle_sync(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
/* clear initial data toggle to DATA0 */
retval = usb_clear_halt(urb->dev, urb->pipe);
if (retval < 0) {
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
return retval;
}
/* transfer 3 data packets, should be DATA0, DATA1, DATA0 */
retval = simple_io(tdev, urb, 1, 0, 0, __func__);
if (retval != 0)
return -EINVAL;
/* clear halt resets device side data toggle, host should react to it */
retval = usb_clear_halt(urb->dev, urb->pipe);
if (retval < 0) {
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
return retval;
}
/* host should use DATA0 again after clear halt */
retval = simple_io(tdev, urb, 1, 0, 0, __func__);
return retval;
}
static int halt_simple(struct usbtest_dev *dev)
{
int ep;
@ -1742,6 +1771,33 @@ done:
return retval;
}
static int toggle_sync_simple(struct usbtest_dev *dev)
{
int ep;
int retval = 0;
struct urb *urb;
struct usb_device *udev = testdev_to_usbdev(dev);
unsigned maxp = get_maxpacket(udev, dev->out_pipe);
/*
* Create a URB that causes a transfer of uneven amount of data packets
* This way the clear toggle has an impact on the data toggle sequence.
* Use 2 maxpacket length packets and one zero packet.
*/
urb = simple_alloc_urb(udev, 0, 2 * maxp, 0);
if (urb == NULL)
return -ENOMEM;
urb->transfer_flags |= URB_ZERO_PACKET;
ep = usb_pipeendpoint(dev->out_pipe);
urb->pipe = dev->out_pipe;
retval = test_toggle_sync(dev, ep, urb);
simple_free_urb(urb);
return retval;
}
/*-------------------------------------------------------------------------*/
/* Control OUT tests use the vendor control requests from Intel's
@ -2524,6 +2580,20 @@ usbtest_do_ioctl(struct usb_interface *intf, struct usbtest_param_32 *param)
retval = test_queue(dev, param,
dev->in_pipe, NULL, 0);
break;
/* Test data Toggle/seq_nr clear between bulk out transfers */
case 29:
if (dev->out_pipe == 0)
break;
retval = 0;
dev_info(&intf->dev, "TEST 29: Clear toggle between bulk writes %d times\n",
param->iterations);
for (i = param->iterations; retval == 0 && i > 0; --i)
retval = toggle_sync_simple(dev);
if (retval)
ERROR(dev, "toggle sync failed, iterations left %d\n",
i);
break;
}
return retval;
}

View file

@ -229,7 +229,10 @@ struct otg_switch_mtk {
* @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
* disable u3port0, bit1==1 to disable u3port1,... etc
* @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode
* @uwk_en: it's true when supports remote wakeup in host mode
* @uwk: syscon including usb wakeup glue layer between SSUSB IP and SPM
* @uwk_reg_base: the base address of the wakeup glue layer in @uwk
* @uwk_vers: the version of the wakeup glue layer
*/
struct ssusb_mtk {
struct device *dev;
@ -253,8 +256,10 @@ struct ssusb_mtk {
int u3p_dis_msk;
struct dentry *dbgfs_root;
/* usb wakeup for host mode */
bool wakeup_en;
struct regmap *pericfg;
bool uwk_en;
struct regmap *uwk;
u32 uwk_reg_base;
u32 uwk_vers;
};
/**

View file

@ -18,8 +18,7 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
struct device_node *dn);
int ssusb_host_enable(struct ssusb_mtk *ssusb);
int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend);
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb);
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb);
void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable);
#else
@ -49,12 +48,7 @@ static inline int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
return 0;
}
static inline int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{
return 0;
}
static inline void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
static inline void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable)
{}
#endif

View file

@ -18,66 +18,77 @@
#include "mtu3.h"
#include "mtu3_dr.h"
#define PERI_WK_CTRL1 0x404
#define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26)
#define UWK_CTL1_IS_E BIT(25)
#define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */
#define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */
#define UWK_CTL1_IDDIG_P BIT(9) /* polarity */
#define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */
/* mt8173 etc */
#define PERI_WK_CTRL1 0x4
#define WC1_IS_C(x) (((x) & 0xf) << 26) /* cycle debounce */
#define WC1_IS_EN BIT(25)
#define WC1_IS_P BIT(6) /* polarity for ip sleep */
/* mt2712 etc */
#define PERI_SSUSB_SPM_CTRL 0x0
#define SSC_IP_SLEEP_EN BIT(4)
#define SSC_SPM_INT_EN BIT(1)
enum ssusb_uwk_vers {
SSUSB_UWK_V1 = 1,
SSUSB_UWK_V2,
};
/*
* ip-sleep wakeup mode:
* all clocks can be turn off, but power domain should be kept on
*/
static void ssusb_wakeup_ip_sleep_en(struct ssusb_mtk *ssusb)
static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
{
u32 tmp;
struct regmap *pericfg = ssusb->pericfg;
u32 reg, msk, val;
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_IS_P;
tmp &= ~(UWK_CTL1_IS_C(0xf));
tmp |= UWK_CTL1_IS_C(0x8);
regmap_write(pericfg, PERI_WK_CTRL1, tmp);
regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
dev_dbg(ssusb->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
__func__, tmp);
}
static void ssusb_wakeup_ip_sleep_dis(struct ssusb_mtk *ssusb)
{
u32 tmp;
regmap_read(ssusb->pericfg, PERI_WK_CTRL1, &tmp);
tmp &= ~UWK_CTL1_IS_E;
regmap_write(ssusb->pericfg, PERI_WK_CTRL1, tmp);
switch (ssusb->uwk_vers) {
case SSUSB_UWK_V1:
reg = ssusb->uwk_reg_base + PERI_WK_CTRL1;
msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P;
val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0;
break;
case SSUSB_UWK_V2:
reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
val = enable ? msk : 0;
break;
default:
return;
}
regmap_update_bits(ssusb->uwk, reg, msk, val);
}
int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
struct device_node *dn)
{
struct device *dev = ssusb->dev;
struct of_phandle_args args;
int ret;
/*
* Wakeup function is optional, so it is not an error if this property
* does not exist, and in such case, no need to get relative
* properties anymore.
*/
ssusb->wakeup_en = of_property_read_bool(dn, "mediatek,enable-wakeup");
if (!ssusb->wakeup_en)
/* wakeup function is optional */
ssusb->uwk_en = of_property_read_bool(dn, "wakeup-source");
if (!ssusb->uwk_en)
return 0;
ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
"mediatek,syscon-wakeup");
if (IS_ERR(ssusb->pericfg)) {
dev_err(dev, "fail to get pericfg regs\n");
return PTR_ERR(ssusb->pericfg);
}
ret = of_parse_phandle_with_fixed_args(dn,
"mediatek,syscon-wakeup", 2, 0, &args);
if (ret)
return ret;
return 0;
ssusb->uwk_reg_base = args.args[0];
ssusb->uwk_vers = args.args[1];
ssusb->uwk = syscon_node_to_regmap(args.np);
of_node_put(args.np);
dev_info(ssusb->dev, "uwk - reg:0x%x, version:%d\n",
ssusb->uwk_reg_base, ssusb->uwk_vers);
return PTR_ERR_OR_ZERO(ssusb->uwk);
}
void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable)
{
if (ssusb->uwk_en)
ssusb_wakeup_ip_sleep_set(ssusb, enable);
}
static void host_ports_num_get(struct ssusb_mtk *ssusb)
@ -235,17 +246,3 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
of_platform_depopulate(ssusb->dev);
ssusb_host_cleanup(ssusb);
}
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{
if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_en(ssusb);
return 0;
}
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
{
if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_dis(ssusb);
}

View file

@ -282,8 +282,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
/* if host role is supported */
ret = ssusb_wakeup_of_property_parse(ssusb, node);
if (ret)
if (ret) {
dev_err(dev, "failed to parse uwk property\n");
return ret;
}
/* optional property, ignore the error if it does not exist */
of_property_read_u32(node, "mediatek,u3p-dis-msk",
@ -308,7 +310,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) {
dev_err(ssusb->dev, "couldn't get extcon device\n");
return -EPROBE_DEFER;
return PTR_ERR(otg_sx->edev);
}
}
@ -457,7 +459,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
ssusb_host_disable(ssusb, true);
ssusb_phy_power_off(ssusb);
ssusb_clks_disable(ssusb);
ssusb_wakeup_enable(ssusb);
ssusb_wakeup_set(ssusb, true);
return 0;
}
@ -473,7 +475,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
if (!ssusb->is_host)
return 0;
ssusb_wakeup_disable(ssusb);
ssusb_wakeup_set(ssusb, false);
ret = ssusb_clks_enable(ssusb);
if (ret)
goto clks_err;

View file

@ -520,7 +520,7 @@ static int da8xx_probe(struct platform_device *pdev)
if (!glue)
return -ENOMEM;
clk = devm_clk_get(&pdev->dev, "usb20");
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(clk);

View file

@ -1687,7 +1687,7 @@ EXPORT_SYMBOL_GPL(musb_mailbox);
/*-------------------------------------------------------------------------*/
static ssize_t
musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
@ -1701,7 +1701,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
musb_mode_store(struct device *dev, struct device_attribute *attr,
mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
struct musb *musb = dev_to_musb(dev);
@ -1721,10 +1721,10 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
return (status == 0) ? n : status;
}
static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
static DEVICE_ATTR_RW(mode);
static ssize_t
musb_vbus_store(struct device *dev, struct device_attribute *attr,
vbus_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
struct musb *musb = dev_to_musb(dev);
@ -1748,7 +1748,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
}
static ssize_t
musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
@ -1773,13 +1773,12 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "Vbus %s, timeout %lu msec\n",
vbus ? "on" : "off", val);
}
static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
static DEVICE_ATTR_RW(vbus);
/* Gadget drivers can't know that a host is connected so they might want
* to start SRP, but users can. This allows userspace to trigger SRP.
*/
static ssize_t
musb_srp_store(struct device *dev, struct device_attribute *attr,
static ssize_t srp_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
struct musb *musb = dev_to_musb(dev);
@ -1796,7 +1795,7 @@ musb_srp_store(struct device *dev, struct device_attribute *attr,
return n;
}
static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
static DEVICE_ATTR_WO(srp);
static struct attribute *musb_attributes[] = {
&dev_attr_mode.attr,

View file

@ -195,7 +195,6 @@ static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
static void
musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
{
u16 frame;
u32 len;
void __iomem *mbase = musb->mregs;
struct urb *urb = next_urb(qh);
@ -244,7 +243,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
musb_dbg(musb, "check whether there's still time for periodic Tx");
frame = musb_readw(mbase, MUSB_FRAME);
/* FIXME this doesn't implement that scheduling policy ...
* or handle framecounter wrapping
*/
@ -1781,7 +1779,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
struct musb_qh *qh = hw_ep->in_qh;
size_t xfer_len;
void __iomem *mbase = musb->mregs;
int pipe;
u16 rx_csr, val;
bool iso_err = false;
bool done = false;
@ -1810,8 +1807,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
return;
}
pipe = urb->pipe;
trace_musb_urb_rx(musb, urb);
/* check for errors, concurrent stall & unlink is not really

View file

@ -519,7 +519,7 @@ static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
}
static ssize_t
get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%d\n",
@ -527,7 +527,7 @@ get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
set_a_bus_req(struct device *dev, struct device_attribute *attr,
a_bus_req_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
@ -559,11 +559,10 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req,
set_a_bus_req);
static DEVICE_ATTR_RW(a_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
a_clr_err_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
@ -587,10 +586,10 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static DEVICE_ATTR_WO(a_clr_err);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr,
a_bus_drop_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
@ -599,7 +598,7 @@ get_a_bus_drop(struct device *dev, struct device_attribute *attr,
}
static ssize_t
set_a_bus_drop(struct device *dev, struct device_attribute *attr,
a_bus_drop_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
@ -630,8 +629,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR,
get_a_bus_drop, set_a_bus_drop);
static DEVICE_ATTR_RW(a_bus_drop);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,

View file

@ -59,13 +59,13 @@ static const unsigned int tahvo_cable[] = {
EXTCON_NONE,
};
static ssize_t vbus_state_show(struct device *device,
static ssize_t vbus_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct tahvo_usb *tu = dev_get_drvdata(device);
return sprintf(buf, "%s\n", tu->vbus_state ? "on" : "off");
}
static DEVICE_ATTR(vbus, 0444, vbus_state_show, NULL);
static DEVICE_ATTR_RO(vbus);
static void check_vbus_state(struct tahvo_usb *tu)
{
@ -310,7 +310,7 @@ static ssize_t otg_mode_store(struct device *device,
return r;
}
static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
static DEVICE_ATTR_RW(otg_mode);
static struct attribute *tahvo_attributes[] = {
&dev_attr_vbus.attr,

View file

@ -168,7 +168,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
return 0;
}
static ssize_t twl6030_usb_vbus_show(struct device *dev,
static ssize_t vbus_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct twl6030_usb *twl = dev_get_drvdata(dev);
@ -194,7 +194,7 @@ static ssize_t twl6030_usb_vbus_show(struct device *dev,
return ret;
}
static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
static DEVICE_ATTR_RO(vbus);
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{

View file

@ -323,6 +323,14 @@ static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
return *phy == match_data;
}
static void usb_charger_init(struct usb_phy *usb_phy)
{
usb_phy->chg_type = UNKNOWN_TYPE;
usb_phy->chg_state = USB_CHARGER_DEFAULT;
usb_phy_set_default_current(usb_phy);
INIT_WORK(&usb_phy->chg_work, usb_phy_notify_charger_work);
}
static int usb_add_extcon(struct usb_phy *x)
{
int ret;
@ -406,10 +414,6 @@ static int usb_add_extcon(struct usb_phy *x)
}
}
usb_phy_set_default_current(x);
INIT_WORK(&x->chg_work, usb_phy_notify_charger_work);
x->chg_type = UNKNOWN_TYPE;
x->chg_state = USB_CHARGER_DEFAULT;
if (x->type_nb.notifier_call)
__usb_phy_get_charger_type(x);
@ -704,6 +708,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
return -EINVAL;
}
usb_charger_init(x);
ret = usb_add_extcon(x);
if (ret)
return ret;
@ -749,6 +754,7 @@ int usb_add_phy_dev(struct usb_phy *x)
return -EINVAL;
}
usb_charger_init(x);
ret = usb_add_extcon(x);
if (ret)
return ret;

View file

@ -5,7 +5,7 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
renesas_usbhs-y += mod_host.o

View file

@ -17,6 +17,7 @@
#include "common.h"
#include "rcar2.h"
#include "rcar3.h"
#include "rza.h"
/*
* image of renesas_usbhs
@ -488,6 +489,10 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,rcar-gen3-usbhs",
.data = (void *)USBHS_TYPE_RCAR_GEN3,
},
{
.compatible = "renesas,rza1-usbhs",
.data = (void *)USBHS_TYPE_RZA1,
},
{ },
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
@ -520,6 +525,11 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
if (dparam->type == USBHS_TYPE_RZA1) {
dparam->pipe_configs = usbhsc_new_pipe;
dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
return info;
}
@ -581,6 +591,18 @@ static int usbhs_probe(struct platform_device *pdev)
break;
case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
priv->pfunc = usbhs_rcar3_with_pll_ops;
if (!IS_ERR_OR_NULL(priv->edev)) {
priv->nb.notifier_call = priv->pfunc.notifier;
ret = devm_extcon_register_notifier(&pdev->dev,
priv->edev,
EXTCON_USB_HOST,
&priv->nb);
if (ret < 0)
dev_err(&pdev->dev, "no notifier registered\n");
}
break;
case USBHS_TYPE_RZA1:
priv->pfunc = usbhs_rza1_ops;
break;
default:
if (!info->platform_callback.get_id) {

Some files were not shown because too many files have changed in this diff Show more