scsi: hisi_sas: Reduce HISI_SAS_SGE_PAGE_CNT in size
[linux-2.6-microblaze.git] / drivers / thunderbolt / lc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Thunderbolt link controller support
4  *
5  * Copyright (C) 2019, Intel Corporation
6  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
7  */
8
9 #include "tb.h"
10
11 /**
12  * tb_lc_read_uuid() - Read switch UUID from link controller common register
13  * @sw: Switch whose UUID is read
14  * @uuid: UUID is placed here
15  */
16 int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid)
17 {
18         if (!sw->cap_lc)
19                 return -EINVAL;
20         return tb_sw_read(sw, uuid, TB_CFG_SWITCH, sw->cap_lc + TB_LC_FUSE, 4);
21 }
22
23 static int read_lc_desc(struct tb_switch *sw, u32 *desc)
24 {
25         if (!sw->cap_lc)
26                 return -EINVAL;
27         return tb_sw_read(sw, desc, TB_CFG_SWITCH, sw->cap_lc + TB_LC_DESC, 1);
28 }
29
30 static int find_port_lc_cap(struct tb_port *port)
31 {
32         struct tb_switch *sw = port->sw;
33         int start, phys, ret, size;
34         u32 desc;
35
36         ret = read_lc_desc(sw, &desc);
37         if (ret)
38                 return ret;
39
40         /* Start of port LC registers */
41         start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
42         size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
43         phys = tb_phy_port_from_link(port->port);
44
45         return sw->cap_lc + start + phys * size;
46 }
47
48 static int tb_lc_configure_lane(struct tb_port *port, bool configure)
49 {
50         bool upstream = tb_is_upstream_port(port);
51         struct tb_switch *sw = port->sw;
52         u32 ctrl, lane;
53         int cap, ret;
54
55         if (sw->generation < 2)
56                 return 0;
57
58         cap = find_port_lc_cap(port);
59         if (cap < 0)
60                 return cap;
61
62         ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
63         if (ret)
64                 return ret;
65
66         /* Resolve correct lane */
67         if (port->port % 2)
68                 lane = TB_LC_SX_CTRL_L1C;
69         else
70                 lane = TB_LC_SX_CTRL_L2C;
71
72         if (configure) {
73                 ctrl |= lane;
74                 if (upstream)
75                         ctrl |= TB_LC_SX_CTRL_UPSTREAM;
76         } else {
77                 ctrl &= ~lane;
78                 if (upstream)
79                         ctrl &= ~TB_LC_SX_CTRL_UPSTREAM;
80         }
81
82         return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
83 }
84
85 /**
86  * tb_lc_configure_link() - Let LC know about configured link
87  * @sw: Switch that is being added
88  *
89  * Informs LC of both parent switch and @sw that there is established
90  * link between the two.
91  */
92 int tb_lc_configure_link(struct tb_switch *sw)
93 {
94         struct tb_port *up, *down;
95         int ret;
96
97         if (!sw->config.enabled || !tb_route(sw))
98                 return 0;
99
100         up = tb_upstream_port(sw);
101         down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
102
103         /* Configure parent link toward this switch */
104         ret = tb_lc_configure_lane(down, true);
105         if (ret)
106                 return ret;
107
108         /* Configure upstream link from this switch to the parent */
109         ret = tb_lc_configure_lane(up, true);
110         if (ret)
111                 tb_lc_configure_lane(down, false);
112
113         return ret;
114 }
115
116 /**
117  * tb_lc_unconfigure_link() - Let LC know about unconfigured link
118  * @sw: Switch to unconfigure
119  *
120  * Informs LC of both parent switch and @sw that the link between the
121  * two does not exist anymore.
122  */
123 void tb_lc_unconfigure_link(struct tb_switch *sw)
124 {
125         struct tb_port *up, *down;
126
127         if (sw->is_unplugged || !sw->config.enabled || !tb_route(sw))
128                 return;
129
130         up = tb_upstream_port(sw);
131         down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
132
133         tb_lc_configure_lane(up, false);
134         tb_lc_configure_lane(down, false);
135 }
136
137 /**
138  * tb_lc_set_sleep() - Inform LC that the switch is going to sleep
139  * @sw: Switch to set sleep
140  *
141  * Let the switch link controllers know that the switch is going to
142  * sleep.
143  */
144 int tb_lc_set_sleep(struct tb_switch *sw)
145 {
146         int start, size, nlc, ret, i;
147         u32 desc;
148
149         if (sw->generation < 2)
150                 return 0;
151
152         ret = read_lc_desc(sw, &desc);
153         if (ret)
154                 return ret;
155
156         /* Figure out number of link controllers */
157         nlc = desc & TB_LC_DESC_NLC_MASK;
158         start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
159         size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
160
161         /* For each link controller set sleep bit */
162         for (i = 0; i < nlc; i++) {
163                 unsigned int offset = sw->cap_lc + start + i * size;
164                 u32 ctrl;
165
166                 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH,
167                                  offset + TB_LC_SX_CTRL, 1);
168                 if (ret)
169                         return ret;
170
171                 ctrl |= TB_LC_SX_CTRL_SLP;
172                 ret = tb_sw_write(sw, &ctrl, TB_CFG_SWITCH,
173                                   offset + TB_LC_SX_CTRL, 1);
174                 if (ret)
175                         return ret;
176         }
177
178         return 0;
179 }