summaryrefslogtreecommitdiffstats
path: root/drivers/ntb/hw
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-08-03 14:19:50 -0400
committerJon Mason <jdmason@kudzu.us>2017-11-18 20:37:12 -0500
commit0ee28f26f378b31e87d35ae7a33e9b50b3283c84 (patch)
tree70cc7cc97a8032c8c39a7cc87910071e73217922 /drivers/ntb/hw
parente099b45b7c27b4fc6510918ea8c7d18980787283 (diff)
NTB: switchtec_ntb: Add link management
switchtec_ntb checks for a link by looking at the shared memory window. If the magic number is correct and the other side indicates their link is enabled then we take the link to be up. Whenever we change our local link status we send a msg to the other side to check whether it's up and change their status. The current status is maintained in a flag so ntb_is_link_up can return quickly. We utilize Switchtec's link status notifier to also check link changes when the switch notices a port changes state. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Reviewed-by: Stephen Bates <sbates@raithlin.com> Reviewed-by: Kurt Schwemmer <kurt.schwemmer@microsemi.com> Acked-by: Allen Hubbe <Allen.Hubbe@dell.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/ntb/hw')
-rw-r--r--drivers/ntb/hw/mscc/ntb_hw_switchtec.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
index 158ed310cbaf..b477a8915245 100644
--- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
+++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
@@ -64,6 +64,7 @@ static inline void _iowrite64(u64 val, void __iomem *mmio)
64 64
65struct shared_mw { 65struct shared_mw {
66 u32 magic; 66 u32 magic;
67 u32 link_sta;
67 u32 partition_id; 68 u32 partition_id;
68 u64 mw_sizes[MAX_MWS]; 69 u64 mw_sizes[MAX_MWS];
69}; 70};
@@ -104,8 +105,17 @@ struct switchtec_ntb {
104 int peer_nr_direct_mw; 105 int peer_nr_direct_mw;
105 int peer_nr_lut_mw; 106 int peer_nr_lut_mw;
106 int peer_direct_mw_to_bar[MAX_DIRECT_MW]; 107 int peer_direct_mw_to_bar[MAX_DIRECT_MW];
108
109 bool link_is_up;
110 enum ntb_speed link_speed;
111 enum ntb_width link_width;
107}; 112};
108 113
114static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
115{
116 return container_of(ntb, struct switchtec_ntb, ntb);
117}
118
109static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, 119static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
110 struct ntb_ctrl_regs __iomem *ctl, 120 struct ntb_ctrl_regs __iomem *ctl,
111 u32 op, int wait_status) 121 u32 op, int wait_status)
@@ -163,6 +173,17 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
163 return -EIO; 173 return -EIO;
164} 174}
165 175
176static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx,
177 u32 val)
178{
179 if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg))
180 return -EINVAL;
181
182 iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg);
183
184 return 0;
185}
186
166static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 187static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx)
167{ 188{
168 return 0; 189 return 0;
@@ -194,22 +215,124 @@ static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
194 return 0; 215 return 0;
195} 216}
196 217
218static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,
219 int partition,
220 enum ntb_speed *speed,
221 enum ntb_width *width)
222{
223 struct switchtec_dev *stdev = sndev->stdev;
224
225 u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id);
226 u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);
227
228 if (speed)
229 *speed = (linksta >> 16) & 0xF;
230
231 if (width)
232 *width = (linksta >> 20) & 0x3F;
233}
234
235static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev)
236{
237 enum ntb_speed self_speed, peer_speed;
238 enum ntb_width self_width, peer_width;
239
240 if (!sndev->link_is_up) {
241 sndev->link_speed = NTB_SPEED_NONE;
242 sndev->link_width = NTB_WIDTH_NONE;
243 return;
244 }
245
246 switchtec_ntb_part_link_speed(sndev, sndev->self_partition,
247 &self_speed, &self_width);
248 switchtec_ntb_part_link_speed(sndev, sndev->peer_partition,
249 &peer_speed, &peer_width);
250
251 sndev->link_speed = min(self_speed, peer_speed);
252 sndev->link_width = min(self_width, peer_width);
253}
254
255enum {
256 LINK_MESSAGE = 0,
257 MSG_LINK_UP = 1,
258 MSG_LINK_DOWN = 2,
259 MSG_CHECK_LINK = 3,
260};
261
262static void switchtec_ntb_check_link(struct switchtec_ntb *sndev)
263{
264 int link_sta;
265 int old = sndev->link_is_up;
266
267 link_sta = sndev->self_shared->link_sta;
268 if (link_sta) {
269 u64 peer = ioread64(&sndev->peer_shared->magic);
270
271 if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC)
272 link_sta = peer >> 32;
273 else
274 link_sta = 0;
275 }
276
277 sndev->link_is_up = link_sta;
278 switchtec_ntb_set_link_speed(sndev);
279
280 if (link_sta != old) {
281 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK);
282 ntb_link_event(&sndev->ntb);
283 dev_info(&sndev->stdev->dev, "ntb link %s",
284 link_sta ? "up" : "down");
285 }
286}
287
288static void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
289{
290 struct switchtec_ntb *sndev = stdev->sndev;
291
292 switchtec_ntb_check_link(sndev);
293}
294
197static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, 295static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb,
198 enum ntb_speed *speed, 296 enum ntb_speed *speed,
199 enum ntb_width *width) 297 enum ntb_width *width)
200{ 298{
201 return 0; 299 struct switchtec_ntb *sndev = ntb_sndev(ntb);
300
301 if (speed)
302 *speed = sndev->link_speed;
303 if (width)
304 *width = sndev->link_width;
305
306 return sndev->link_is_up;
202} 307}
203 308
204static int switchtec_ntb_link_enable(struct ntb_dev *ntb, 309static int switchtec_ntb_link_enable(struct ntb_dev *ntb,
205 enum ntb_speed max_speed, 310 enum ntb_speed max_speed,
206 enum ntb_width max_width) 311 enum ntb_width max_width)
207{ 312{
313 struct switchtec_ntb *sndev = ntb_sndev(ntb);
314
315 dev_dbg(&sndev->stdev->dev, "enabling link");
316
317 sndev->self_shared->link_sta = 1;
318 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
319
320 switchtec_ntb_check_link(sndev);
321
208 return 0; 322 return 0;
209} 323}
210 324
211static int switchtec_ntb_link_disable(struct ntb_dev *ntb) 325static int switchtec_ntb_link_disable(struct ntb_dev *ntb)
212{ 326{
327 struct switchtec_ntb *sndev = ntb_sndev(ntb);
328
329 dev_dbg(&sndev->stdev->dev, "disabling link");
330
331 sndev->self_shared->link_sta = 0;
332 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
333
334 switchtec_ntb_check_link(sndev);
335
213 return 0; 336 return 0;
214} 337}
215 338
@@ -577,6 +700,9 @@ static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev)
577 dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i, 700 dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i,
578 (u32)msg); 701 (u32)msg);
579 iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); 702 iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status);
703
704 if (i == LINK_MESSAGE)
705 switchtec_ntb_check_link(sndev);
580 } 706 }
581 } 707 }
582 708
@@ -679,6 +805,7 @@ static int switchtec_ntb_add(struct device *dev,
679 goto deinit_and_exit; 805 goto deinit_and_exit;
680 806
681 stdev->sndev = sndev; 807 stdev->sndev = sndev;
808 stdev->link_notifier = switchtec_ntb_link_notification;
682 dev_info(dev, "NTB device registered"); 809 dev_info(dev, "NTB device registered");
683 810
684 return 0; 811 return 0;
@@ -702,6 +829,7 @@ void switchtec_ntb_remove(struct device *dev,
702 if (!sndev) 829 if (!sndev)
703 return; 830 return;
704 831
832 stdev->link_notifier = NULL;
705 stdev->sndev = NULL; 833 stdev->sndev = NULL;
706 ntb_unregister_device(&sndev->ntb); 834 ntb_unregister_device(&sndev->ntb);
707 switchtec_ntb_deinit_db_msg_irq(sndev); 835 switchtec_ntb_deinit_db_msg_irq(sndev);