29
29
* @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion
30
30
* @cmd_lock: Lock to serialize the command interface
31
31
* @resp: command response
32
+ * @link_info: link related information
32
33
* @event_cb: callback for linkchange events
33
34
* @cmd_pend: flag set before new command is started
34
35
* flag cleared after command response is received
@@ -40,6 +41,7 @@ struct lmac {
40
41
wait_queue_head_t wq_cmd_cmplt ;
41
42
struct mutex cmd_lock ;
42
43
u64 resp ;
44
+ struct cgx_link_user_info link_info ;
43
45
struct cgx_event_cb event_cb ;
44
46
bool cmd_pend ;
45
47
struct cgx * cgx ;
@@ -58,6 +60,12 @@ struct cgx {
58
60
59
61
static LIST_HEAD (cgx_list );
60
62
63
+ /* Convert firmware speed encoding to user format(Mbps) */
64
+ static u32 cgx_speed_mbps [CGX_LINK_SPEED_MAX ];
65
+
66
+ /* Convert firmware lmac type encoding to string */
67
+ static char * cgx_lmactype_string [LMAC_MODE_MAX ];
68
+
61
69
/* Supported devices */
62
70
static const struct pci_device_id cgx_id_table [] = {
63
71
{ PCI_DEVICE (PCI_VENDOR_ID_CAVIUM , PCI_DEVID_OCTEONTX2_CGX ) },
@@ -119,6 +127,177 @@ void *cgx_get_pdata(int cgx_id)
119
127
}
120
128
EXPORT_SYMBOL (cgx_get_pdata );
121
129
130
+ /* Ensure the required lock for event queue(where asynchronous events are
131
+ * posted) is acquired before calling this API. Else an asynchronous event(with
132
+ * latest link status) can reach the destination before this function returns
133
+ * and could make the link status appear wrong.
134
+ */
135
+ int cgx_get_link_info (void * cgxd , int lmac_id ,
136
+ struct cgx_link_user_info * linfo )
137
+ {
138
+ struct lmac * lmac = lmac_pdata (lmac_id , cgxd );
139
+
140
+ if (!lmac )
141
+ return - ENODEV ;
142
+
143
+ * linfo = lmac -> link_info ;
144
+ return 0 ;
145
+ }
146
+ EXPORT_SYMBOL (cgx_get_link_info );
147
+
148
+ static u64 mac2u64 (u8 * mac_addr )
149
+ {
150
+ u64 mac = 0 ;
151
+ int index ;
152
+
153
+ for (index = ETH_ALEN - 1 ; index >= 0 ; index -- )
154
+ mac |= ((u64 )* mac_addr ++ ) << (8 * index );
155
+ return mac ;
156
+ }
157
+
158
+ int cgx_lmac_addr_set (u8 cgx_id , u8 lmac_id , u8 * mac_addr )
159
+ {
160
+ struct cgx * cgx_dev = cgx_get_pdata (cgx_id );
161
+ u64 cfg ;
162
+
163
+ /* copy 6bytes from macaddr */
164
+ /* memcpy(&cfg, mac_addr, 6); */
165
+
166
+ cfg = mac2u64 (mac_addr );
167
+
168
+ cgx_write (cgx_dev , 0 , (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8 )),
169
+ cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64 )lmac_id << 49 ));
170
+
171
+ cfg = cgx_read (cgx_dev , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 );
172
+ cfg |= CGX_DMAC_CTL0_CAM_ENABLE ;
173
+ cgx_write (cgx_dev , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 , cfg );
174
+
175
+ return 0 ;
176
+ }
177
+ EXPORT_SYMBOL (cgx_lmac_addr_set );
178
+
179
+ u64 cgx_lmac_addr_get (u8 cgx_id , u8 lmac_id )
180
+ {
181
+ struct cgx * cgx_dev = cgx_get_pdata (cgx_id );
182
+ u64 cfg ;
183
+
184
+ cfg = cgx_read (cgx_dev , 0 , CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8 );
185
+ return cfg & CGX_RX_DMAC_ADR_MASK ;
186
+ }
187
+ EXPORT_SYMBOL (cgx_lmac_addr_get );
188
+
189
+ static inline u8 cgx_get_lmac_type (struct cgx * cgx , int lmac_id )
190
+ {
191
+ u64 cfg ;
192
+
193
+ cfg = cgx_read (cgx , lmac_id , CGXX_CMRX_CFG );
194
+ return (cfg >> CGX_LMAC_TYPE_SHIFT ) & CGX_LMAC_TYPE_MASK ;
195
+ }
196
+
197
+ /* Configure CGX LMAC in internal loopback mode */
198
+ int cgx_lmac_internal_loopback (void * cgxd , int lmac_id , bool enable )
199
+ {
200
+ struct cgx * cgx = cgxd ;
201
+ u8 lmac_type ;
202
+ u64 cfg ;
203
+
204
+ if (!cgx || lmac_id >= cgx -> lmac_count )
205
+ return - ENODEV ;
206
+
207
+ lmac_type = cgx_get_lmac_type (cgx , lmac_id );
208
+ if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII ) {
209
+ cfg = cgx_read (cgx , lmac_id , CGXX_GMP_PCS_MRX_CTL );
210
+ if (enable )
211
+ cfg |= CGXX_GMP_PCS_MRX_CTL_LBK ;
212
+ else
213
+ cfg &= ~CGXX_GMP_PCS_MRX_CTL_LBK ;
214
+ cgx_write (cgx , lmac_id , CGXX_GMP_PCS_MRX_CTL , cfg );
215
+ } else {
216
+ cfg = cgx_read (cgx , lmac_id , CGXX_SPUX_CONTROL1 );
217
+ if (enable )
218
+ cfg |= CGXX_SPUX_CONTROL1_LBK ;
219
+ else
220
+ cfg &= ~CGXX_SPUX_CONTROL1_LBK ;
221
+ cgx_write (cgx , lmac_id , CGXX_SPUX_CONTROL1 , cfg );
222
+ }
223
+ return 0 ;
224
+ }
225
+ EXPORT_SYMBOL (cgx_lmac_internal_loopback );
226
+
227
+ void cgx_lmac_promisc_config (int cgx_id , int lmac_id , bool enable )
228
+ {
229
+ struct cgx * cgx = cgx_get_pdata (cgx_id );
230
+ u64 cfg = 0 ;
231
+
232
+ if (!cgx )
233
+ return ;
234
+
235
+ if (enable ) {
236
+ /* Enable promiscuous mode on LMAC */
237
+ cfg = cgx_read (cgx , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 );
238
+ cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE );
239
+ cfg |= CGX_DMAC_BCAST_MODE ;
240
+ cgx_write (cgx , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 , cfg );
241
+
242
+ cfg = cgx_read (cgx , 0 ,
243
+ (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8 ));
244
+ cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE ;
245
+ cgx_write (cgx , 0 ,
246
+ (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8 ), cfg );
247
+ } else {
248
+ /* Disable promiscuous mode */
249
+ cfg = cgx_read (cgx , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 );
250
+ cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE ;
251
+ cgx_write (cgx , lmac_id , CGXX_CMRX_RX_DMAC_CTL0 , cfg );
252
+ cfg = cgx_read (cgx , 0 ,
253
+ (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8 ));
254
+ cfg |= CGX_DMAC_CAM_ADDR_ENABLE ;
255
+ cgx_write (cgx , 0 ,
256
+ (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8 ), cfg );
257
+ }
258
+ }
259
+ EXPORT_SYMBOL (cgx_lmac_promisc_config );
260
+
261
+ int cgx_get_rx_stats (void * cgxd , int lmac_id , int idx , u64 * rx_stat )
262
+ {
263
+ struct cgx * cgx = cgxd ;
264
+
265
+ if (!cgx || lmac_id >= cgx -> lmac_count )
266
+ return - ENODEV ;
267
+ * rx_stat = cgx_read (cgx , lmac_id , CGXX_CMRX_RX_STAT0 + (idx * 8 ));
268
+ return 0 ;
269
+ }
270
+ EXPORT_SYMBOL (cgx_get_rx_stats );
271
+
272
+ int cgx_get_tx_stats (void * cgxd , int lmac_id , int idx , u64 * tx_stat )
273
+ {
274
+ struct cgx * cgx = cgxd ;
275
+
276
+ if (!cgx || lmac_id >= cgx -> lmac_count )
277
+ return - ENODEV ;
278
+ * tx_stat = cgx_read (cgx , lmac_id , CGXX_CMRX_TX_STAT0 + (idx * 8 ));
279
+ return 0 ;
280
+ }
281
+ EXPORT_SYMBOL (cgx_get_tx_stats );
282
+
283
+ int cgx_lmac_rx_tx_enable (void * cgxd , int lmac_id , bool enable )
284
+ {
285
+ struct cgx * cgx = cgxd ;
286
+ u64 cfg ;
287
+
288
+ if (!cgx || lmac_id >= cgx -> lmac_count )
289
+ return - ENODEV ;
290
+
291
+ cfg = cgx_read (cgx , lmac_id , CGXX_CMRX_CFG );
292
+ if (enable )
293
+ cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN ;
294
+ else
295
+ cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN );
296
+ cgx_write (cgx , lmac_id , CGXX_CMRX_CFG , cfg );
297
+ return 0 ;
298
+ }
299
+ EXPORT_SYMBOL (cgx_lmac_rx_tx_enable );
300
+
122
301
/* CGX Firmware interface low level support */
123
302
static int cgx_fwi_cmd_send (u64 req , u64 * resp , struct lmac * lmac )
124
303
{
@@ -191,36 +370,79 @@ static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp,
191
370
return err ;
192
371
}
193
372
373
+ static inline void cgx_link_usertable_init (void )
374
+ {
375
+ cgx_speed_mbps [CGX_LINK_NONE ] = 0 ;
376
+ cgx_speed_mbps [CGX_LINK_10M ] = 10 ;
377
+ cgx_speed_mbps [CGX_LINK_100M ] = 100 ;
378
+ cgx_speed_mbps [CGX_LINK_1G ] = 1000 ;
379
+ cgx_speed_mbps [CGX_LINK_2HG ] = 2500 ;
380
+ cgx_speed_mbps [CGX_LINK_5G ] = 5000 ;
381
+ cgx_speed_mbps [CGX_LINK_10G ] = 10000 ;
382
+ cgx_speed_mbps [CGX_LINK_20G ] = 20000 ;
383
+ cgx_speed_mbps [CGX_LINK_25G ] = 25000 ;
384
+ cgx_speed_mbps [CGX_LINK_40G ] = 40000 ;
385
+ cgx_speed_mbps [CGX_LINK_50G ] = 50000 ;
386
+ cgx_speed_mbps [CGX_LINK_100G ] = 100000 ;
387
+
388
+ cgx_lmactype_string [LMAC_MODE_SGMII ] = "SGMII" ;
389
+ cgx_lmactype_string [LMAC_MODE_XAUI ] = "XAUI" ;
390
+ cgx_lmactype_string [LMAC_MODE_RXAUI ] = "RXAUI" ;
391
+ cgx_lmactype_string [LMAC_MODE_10G_R ] = "10G_R" ;
392
+ cgx_lmactype_string [LMAC_MODE_40G_R ] = "40G_R" ;
393
+ cgx_lmactype_string [LMAC_MODE_QSGMII ] = "QSGMII" ;
394
+ cgx_lmactype_string [LMAC_MODE_25G_R ] = "25G_R" ;
395
+ cgx_lmactype_string [LMAC_MODE_50G_R ] = "50G_R" ;
396
+ cgx_lmactype_string [LMAC_MODE_100G_R ] = "100G_R" ;
397
+ cgx_lmactype_string [LMAC_MODE_USXGMII ] = "USXGMII" ;
398
+ }
399
+
400
+ static inline void link_status_user_format (u64 lstat ,
401
+ struct cgx_link_user_info * linfo ,
402
+ struct cgx * cgx , u8 lmac_id )
403
+ {
404
+ char * lmac_string ;
405
+
406
+ linfo -> link_up = FIELD_GET (RESP_LINKSTAT_UP , lstat );
407
+ linfo -> full_duplex = FIELD_GET (RESP_LINKSTAT_FDUPLEX , lstat );
408
+ linfo -> speed = cgx_speed_mbps [FIELD_GET (RESP_LINKSTAT_SPEED , lstat )];
409
+ linfo -> lmac_type_id = cgx_get_lmac_type (cgx , lmac_id );
410
+ lmac_string = cgx_lmactype_string [linfo -> lmac_type_id ];
411
+ strncpy (linfo -> lmac_type , lmac_string , LMACTYPE_STR_LEN - 1 );
412
+ }
413
+
194
414
/* Hardware event handlers */
195
415
static inline void cgx_link_change_handler (u64 lstat ,
196
416
struct lmac * lmac )
197
417
{
418
+ struct cgx_link_user_info * linfo ;
198
419
struct cgx * cgx = lmac -> cgx ;
199
420
struct cgx_link_event event ;
200
421
struct device * dev ;
422
+ int err_type ;
201
423
202
424
dev = & cgx -> pdev -> dev ;
203
425
204
- event .lstat .link_up = FIELD_GET (RESP_LINKSTAT_UP , lstat );
205
- event .lstat .full_duplex = FIELD_GET (RESP_LINKSTAT_FDUPLEX , lstat );
206
- event .lstat .speed = FIELD_GET (RESP_LINKSTAT_SPEED , lstat );
207
- event .lstat .err_type = FIELD_GET (RESP_LINKSTAT_ERRTYPE , lstat );
426
+ link_status_user_format (lstat , & event .link_uinfo , cgx , lmac -> lmac_id );
427
+ err_type = FIELD_GET (RESP_LINKSTAT_ERRTYPE , lstat );
208
428
209
429
event .cgx_id = cgx -> cgx_id ;
210
430
event .lmac_id = lmac -> lmac_id ;
211
431
432
+ /* update the local copy of link status */
433
+ lmac -> link_info = event .link_uinfo ;
434
+ linfo = & lmac -> link_info ;
435
+
212
436
if (!lmac -> event_cb .notify_link_chg ) {
213
437
dev_dbg (dev , "cgx port %d:%d Link change handler null" ,
214
438
cgx -> cgx_id , lmac -> lmac_id );
215
- if (event . lstat . err_type != CGX_ERR_NONE ) {
439
+ if (err_type != CGX_ERR_NONE ) {
216
440
dev_err (dev , "cgx port %d:%d Link error %d\n" ,
217
- cgx -> cgx_id , lmac -> lmac_id ,
218
- event .lstat .err_type );
441
+ cgx -> cgx_id , lmac -> lmac_id , err_type );
219
442
}
220
- dev_info (dev , "cgx port %d:%d Link status %s, speed %x \n" ,
443
+ dev_info (dev , "cgx port %d:%d Link is %s %d Mbps \n" ,
221
444
cgx -> cgx_id , lmac -> lmac_id ,
222
- event .lstat .link_up ? "UP" : "DOWN" ,
223
- event .lstat .speed );
445
+ linfo -> link_up ? "UP" : "DOWN" , linfo -> speed );
224
446
return ;
225
447
}
226
448
@@ -448,6 +670,8 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
448
670
list_add (& cgx -> cgx_list , & cgx_list );
449
671
cgx -> cgx_id = cgx_get_cgx_cnt () - 1 ;
450
672
673
+ cgx_link_usertable_init ();
674
+
451
675
err = cgx_lmac_init (cgx );
452
676
if (err )
453
677
goto err_release_lmac ;
0 commit comments