1 // SPDX-License-Identifier: GPL-2.0 2 /* Marvell OcteonTx2 CGX driver 3 * 4 * Copyright (C) 2018 Marvell International Ltd. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 #include <linux/acpi.h> 12 #include <linux/module.h> 13 #include <linux/interrupt.h> 14 #include <linux/pci.h> 15 #include <linux/netdevice.h> 16 #include <linux/etherdevice.h> 17 #include <linux/phy.h> 18 #include <linux/of.h> 19 #include <linux/of_mdio.h> 20 #include <linux/of_net.h> 21 22 #include "cgx.h" 23 24 #define DRV_NAME "octeontx2-cgx" 25 #define DRV_STRING "Marvell OcteonTX2 CGX/MAC Driver" 26 27 /** 28 * struct lmac 29 * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion 30 * @cmd_lock: Lock to serialize the command interface 31 * @resp: command response 32 * @link_info: link related information 33 * @event_cb: callback for linkchange events 34 * @event_cb_lock: lock for serializing callback with unregister 35 * @cmd_pend: flag set before new command is started 36 * flag cleared after command response is received 37 * @cgx: parent cgx port 38 * @lmac_id: lmac port id 39 * @name: lmac port name 40 */ 41 struct lmac { 42 wait_queue_head_t wq_cmd_cmplt; 43 struct mutex cmd_lock; 44 u64 resp; 45 struct cgx_link_user_info link_info; 46 struct cgx_event_cb event_cb; 47 spinlock_t event_cb_lock; 48 bool cmd_pend; 49 struct cgx *cgx; 50 u8 lmac_id; 51 char *name; 52 }; 53 54 struct cgx { 55 void __iomem *reg_base; 56 struct pci_dev *pdev; 57 u8 cgx_id; 58 u8 lmac_count; 59 struct lmac *lmac_idmap[MAX_LMAC_PER_CGX]; 60 struct work_struct cgx_cmd_work; 61 struct workqueue_struct *cgx_cmd_workq; 62 struct list_head cgx_list; 63 }; 64 65 static LIST_HEAD(cgx_list); 66 67 /* Convert firmware speed encoding to user format(Mbps) */ 68 static u32 cgx_speed_mbps[CGX_LINK_SPEED_MAX]; 69 70 /* Convert firmware lmac type encoding to string */ 71 static char *cgx_lmactype_string[LMAC_MODE_MAX]; 72 73 /* CGX PHY management internal APIs */ 74 static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en); 75 76 /* Supported devices */ 77 static const struct pci_device_id cgx_id_table[] = { 78 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, 79 { 0, } /* end of table */ 80 }; 81 82 MODULE_DEVICE_TABLE(pci, cgx_id_table); 83 84 static void cgx_write(struct cgx *cgx, u64 lmac, u64 offset, u64 val) 85 { 86 writeq(val, cgx->reg_base + (lmac << 18) + offset); 87 } 88 89 static u64 cgx_read(struct cgx *cgx, u64 lmac, u64 offset) 90 { 91 return readq(cgx->reg_base + (lmac << 18) + offset); 92 } 93 94 static inline struct lmac *lmac_pdata(u8 lmac_id, struct cgx *cgx) 95 { 96 if (!cgx || lmac_id >= MAX_LMAC_PER_CGX) 97 return NULL; 98 99 return cgx->lmac_idmap[lmac_id]; 100 } 101 102 int cgx_get_cgxcnt_max(void) 103 { 104 struct cgx *cgx_dev; 105 int idmax = -ENODEV; 106 107 list_for_each_entry(cgx_dev, &cgx_list, cgx_list) 108 if (cgx_dev->cgx_id > idmax) 109 idmax = cgx_dev->cgx_id; 110 111 if (idmax < 0) 112 return 0; 113 114 return idmax + 1; 115 } 116 EXPORT_SYMBOL(cgx_get_cgxcnt_max); 117 118 int cgx_get_lmac_cnt(void *cgxd) 119 { 120 struct cgx *cgx = cgxd; 121 122 if (!cgx) 123 return -ENODEV; 124 125 return cgx->lmac_count; 126 } 127 EXPORT_SYMBOL(cgx_get_lmac_cnt); 128 129 void *cgx_get_pdata(int cgx_id) 130 { 131 struct cgx *cgx_dev; 132 133 list_for_each_entry(cgx_dev, &cgx_list, cgx_list) { 134 if (cgx_dev->cgx_id == cgx_id) 135 return cgx_dev; 136 } 137 return NULL; 138 } 139 EXPORT_SYMBOL(cgx_get_pdata); 140 141 int cgx_get_cgxid(void *cgxd) 142 { 143 struct cgx *cgx = cgxd; 144 145 if (!cgx) 146 return -EINVAL; 147 148 return cgx->cgx_id; 149 } 150 151 /* Ensure the required lock for event queue(where asynchronous events are 152 * posted) is acquired before calling this API. Else an asynchronous event(with 153 * latest link status) can reach the destination before this function returns 154 * and could make the link status appear wrong. 155 */ 156 int cgx_get_link_info(void *cgxd, int lmac_id, 157 struct cgx_link_user_info *linfo) 158 { 159 struct lmac *lmac = lmac_pdata(lmac_id, cgxd); 160 161 if (!lmac) 162 return -ENODEV; 163 164 *linfo = lmac->link_info; 165 return 0; 166 } 167 EXPORT_SYMBOL(cgx_get_link_info); 168 169 static u64 mac2u64 (u8 *mac_addr) 170 { 171 u64 mac = 0; 172 int index; 173 174 for (index = ETH_ALEN - 1; index >= 0; index--) 175 mac |= ((u64)*mac_addr++) << (8 * index); 176 return mac; 177 } 178 179 int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) 180 { 181 struct cgx *cgx_dev = cgx_get_pdata(cgx_id); 182 u64 cfg; 183 184 /* copy 6bytes from macaddr */ 185 /* memcpy(&cfg, mac_addr, 6); */ 186 187 cfg = mac2u64 (mac_addr); 188 189 cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8)), 190 cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49)); 191 192 cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); 193 cfg |= CGX_DMAC_CTL0_CAM_ENABLE; 194 cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); 195 196 return 0; 197 } 198 EXPORT_SYMBOL(cgx_lmac_addr_set); 199 200 u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) 201 { 202 struct cgx *cgx_dev = cgx_get_pdata(cgx_id); 203 u64 cfg; 204 205 cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8); 206 return cfg & CGX_RX_DMAC_ADR_MASK; 207 } 208 EXPORT_SYMBOL(cgx_lmac_addr_get); 209 210 int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind) 211 { 212 struct cgx *cgx = cgxd; 213 214 if (!cgx || lmac_id >= cgx->lmac_count) 215 return -ENODEV; 216 217 cgx_write(cgx, lmac_id, CGXX_CMRX_RX_ID_MAP, (pkind & 0x3F)); 218 return 0; 219 } 220 EXPORT_SYMBOL(cgx_set_pkind); 221 222 static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id) 223 { 224 u64 cfg; 225 226 cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); 227 return (cfg >> CGX_LMAC_TYPE_SHIFT) & CGX_LMAC_TYPE_MASK; 228 } 229 230 /* Configure CGX LMAC in internal loopback mode */ 231 int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable) 232 { 233 struct cgx *cgx = cgxd; 234 u8 lmac_type; 235 u64 cfg; 236 237 if (!cgx || lmac_id >= cgx->lmac_count) 238 return -ENODEV; 239 240 lmac_type = cgx_get_lmac_type(cgx, lmac_id); 241 if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII) { 242 cfg = cgx_read(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL); 243 if (enable) 244 cfg |= CGXX_GMP_PCS_MRX_CTL_LBK; 245 else 246 cfg &= ~CGXX_GMP_PCS_MRX_CTL_LBK; 247 cgx_write(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL, cfg); 248 } else { 249 cfg = cgx_read(cgx, lmac_id, CGXX_SPUX_CONTROL1); 250 if (enable) 251 cfg |= CGXX_SPUX_CONTROL1_LBK; 252 else 253 cfg &= ~CGXX_SPUX_CONTROL1_LBK; 254 cgx_write(cgx, lmac_id, CGXX_SPUX_CONTROL1, cfg); 255 } 256 return 0; 257 } 258 EXPORT_SYMBOL(cgx_lmac_internal_loopback); 259 260 void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) 261 { 262 struct cgx *cgx = cgx_get_pdata(cgx_id); 263 u64 cfg = 0; 264 265 if (!cgx) 266 return; 267 268 if (enable) { 269 /* Enable promiscuous mode on LMAC */ 270 cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); 271 cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE); 272 cfg |= CGX_DMAC_BCAST_MODE; 273 cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); 274 275 cfg = cgx_read(cgx, 0, 276 (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); 277 cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; 278 cgx_write(cgx, 0, 279 (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); 280 } else { 281 /* Disable promiscuous mode */ 282 cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); 283 cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE; 284 cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); 285 cfg = cgx_read(cgx, 0, 286 (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); 287 cfg |= CGX_DMAC_CAM_ADDR_ENABLE; 288 cgx_write(cgx, 0, 289 (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); 290 } 291 } 292 EXPORT_SYMBOL(cgx_lmac_promisc_config); 293 294 /* Enable or disable forwarding received pause frames to Tx block */ 295 void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable) 296 { 297 struct cgx *cgx = cgxd; 298 u64 cfg; 299 300 if (!cgx) 301 return; 302 303 if (enable) { 304 cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL); 305 cfg |= CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK; 306 cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg); 307 308 cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL); 309 cfg |= CGX_SMUX_RX_FRM_CTL_CTL_BCK; 310 cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg); 311 } else { 312 cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL); 313 cfg &= ~CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK; 314 cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg); 315 316 cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL); 317 cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK; 318 cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg); 319 } 320 } 321 EXPORT_SYMBOL(cgx_lmac_enadis_rx_pause_fwding); 322 323 int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) 324 { 325 struct cgx *cgx = cgxd; 326 327 if (!cgx || lmac_id >= cgx->lmac_count) 328 return -ENODEV; 329 *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8)); 330 return 0; 331 } 332 EXPORT_SYMBOL(cgx_get_rx_stats); 333 334 int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat) 335 { 336 struct cgx *cgx = cgxd; 337 338 if (!cgx || lmac_id >= cgx->lmac_count) 339 return -ENODEV; 340 *tx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_TX_STAT0 + (idx * 8)); 341 return 0; 342 } 343 EXPORT_SYMBOL(cgx_get_tx_stats); 344 345 int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) 346 { 347 struct cgx *cgx = cgxd; 348 u64 cfg; 349 350 if (!cgx || lmac_id >= cgx->lmac_count) 351 return -ENODEV; 352 353 cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); 354 if (enable) 355 cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN; 356 else 357 cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN); 358 cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); 359 return 0; 360 } 361 EXPORT_SYMBOL(cgx_lmac_rx_tx_enable); 362 363 int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable) 364 { 365 struct cgx *cgx = cgxd; 366 u64 cfg, last; 367 368 if (!cgx || lmac_id >= cgx->lmac_count) 369 return -ENODEV; 370 371 cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); 372 last = cfg; 373 if (enable) 374 cfg |= DATA_PKT_TX_EN; 375 else 376 cfg &= ~DATA_PKT_TX_EN; 377 378 if (cfg != last) 379 cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); 380 return !!(last & DATA_PKT_TX_EN); 381 } 382 EXPORT_SYMBOL(cgx_lmac_tx_enable); 383 384 /* CGX Firmware interface low level support */ 385 static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac) 386 { 387 struct cgx *cgx = lmac->cgx; 388 struct device *dev; 389 int err = 0; 390 u64 cmd; 391 392 /* Ensure no other command is in progress */ 393 err = mutex_lock_interruptible(&lmac->cmd_lock); 394 if (err) 395 return err; 396 397 /* Ensure command register is free */ 398 cmd = cgx_read(cgx, lmac->lmac_id, CGX_COMMAND_REG); 399 if (FIELD_GET(CMDREG_OWN, cmd) != CGX_CMD_OWN_NS) { 400 err = -EBUSY; 401 goto unlock; 402 } 403 404 /* Update ownership in command request */ 405 req = FIELD_SET(CMDREG_OWN, CGX_CMD_OWN_FIRMWARE, req); 406 407 /* Mark this lmac as pending, before we start */ 408 lmac->cmd_pend = true; 409 410 /* Start command in hardware */ 411 cgx_write(cgx, lmac->lmac_id, CGX_COMMAND_REG, req); 412 413 /* Ensure command is completed without errors */ 414 if (!wait_event_timeout(lmac->wq_cmd_cmplt, !lmac->cmd_pend, 415 msecs_to_jiffies(CGX_CMD_TIMEOUT))) { 416 dev = &cgx->pdev->dev; 417 dev_err(dev, "cgx port %d:%d cmd timeout\n", 418 cgx->cgx_id, lmac->lmac_id); 419 err = -EIO; 420 goto unlock; 421 } 422 423 /* we have a valid command response */ 424 smp_rmb(); /* Ensure the latest updates are visible */ 425 *resp = lmac->resp; 426 427 unlock: 428 mutex_unlock(&lmac->cmd_lock); 429 430 return err; 431 } 432 433 static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp, 434 struct cgx *cgx, int lmac_id) 435 { 436 struct lmac *lmac; 437 int err; 438 439 lmac = lmac_pdata(lmac_id, cgx); 440 if (!lmac) 441 return -ENODEV; 442 443 err = cgx_fwi_cmd_send(req, resp, lmac); 444 445 /* Check for valid response */ 446 if (!err) { 447 if (FIELD_GET(EVTREG_STAT, *resp) == CGX_STAT_FAIL) 448 return -EIO; 449 else 450 return 0; 451 } 452 453 return err; 454 } 455 456 static inline void cgx_link_usertable_init(void) 457 { 458 cgx_speed_mbps[CGX_LINK_NONE] = 0; 459 cgx_speed_mbps[CGX_LINK_10M] = 10; 460 cgx_speed_mbps[CGX_LINK_100M] = 100; 461 cgx_speed_mbps[CGX_LINK_1G] = 1000; 462 cgx_speed_mbps[CGX_LINK_2HG] = 2500; 463 cgx_speed_mbps[CGX_LINK_5G] = 5000; 464 cgx_speed_mbps[CGX_LINK_10G] = 10000; 465 cgx_speed_mbps[CGX_LINK_20G] = 20000; 466 cgx_speed_mbps[CGX_LINK_25G] = 25000; 467 cgx_speed_mbps[CGX_LINK_40G] = 40000; 468 cgx_speed_mbps[CGX_LINK_50G] = 50000; 469 cgx_speed_mbps[CGX_LINK_100G] = 100000; 470 471 cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII"; 472 cgx_lmactype_string[LMAC_MODE_XAUI] = "XAUI"; 473 cgx_lmactype_string[LMAC_MODE_RXAUI] = "RXAUI"; 474 cgx_lmactype_string[LMAC_MODE_10G_R] = "10G_R"; 475 cgx_lmactype_string[LMAC_MODE_40G_R] = "40G_R"; 476 cgx_lmactype_string[LMAC_MODE_QSGMII] = "QSGMII"; 477 cgx_lmactype_string[LMAC_MODE_25G_R] = "25G_R"; 478 cgx_lmactype_string[LMAC_MODE_50G_R] = "50G_R"; 479 cgx_lmactype_string[LMAC_MODE_100G_R] = "100G_R"; 480 cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII"; 481 } 482 483 static inline void link_status_user_format(u64 lstat, 484 struct cgx_link_user_info *linfo, 485 struct cgx *cgx, u8 lmac_id) 486 { 487 char *lmac_string; 488 489 linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); 490 linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); 491 linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)]; 492 linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id); 493 lmac_string = cgx_lmactype_string[linfo->lmac_type_id]; 494 strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1); 495 } 496 497 /* Hardware event handlers */ 498 static inline void cgx_link_change_handler(u64 lstat, 499 struct lmac *lmac) 500 { 501 struct cgx_link_user_info *linfo; 502 struct cgx *cgx = lmac->cgx; 503 struct cgx_link_event event; 504 struct device *dev; 505 int err_type; 506 507 dev = &cgx->pdev->dev; 508 509 link_status_user_format(lstat, &event.link_uinfo, cgx, lmac->lmac_id); 510 err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat); 511 512 event.cgx_id = cgx->cgx_id; 513 event.lmac_id = lmac->lmac_id; 514 515 /* update the local copy of link status */ 516 lmac->link_info = event.link_uinfo; 517 linfo = &lmac->link_info; 518 519 /* Ensure callback doesn't get unregistered until we finish it */ 520 spin_lock(&lmac->event_cb_lock); 521 522 if (!lmac->event_cb.notify_link_chg) { 523 dev_dbg(dev, "cgx port %d:%d Link change handler null", 524 cgx->cgx_id, lmac->lmac_id); 525 if (err_type != CGX_ERR_NONE) { 526 dev_err(dev, "cgx port %d:%d Link error %d\n", 527 cgx->cgx_id, lmac->lmac_id, err_type); 528 } 529 dev_info(dev, "cgx port %d:%d Link is %s %d Mbps\n", 530 cgx->cgx_id, lmac->lmac_id, 531 linfo->link_up ? "UP" : "DOWN", linfo->speed); 532 goto err; 533 } 534 535 if (lmac->event_cb.notify_link_chg(&event, lmac->event_cb.data)) 536 dev_err(dev, "event notification failure\n"); 537 err: 538 spin_unlock(&lmac->event_cb_lock); 539 } 540 541 static inline bool cgx_cmdresp_is_linkevent(u64 event) 542 { 543 u8 id; 544 545 id = FIELD_GET(EVTREG_ID, event); 546 if (id == CGX_CMD_LINK_BRING_UP || 547 id == CGX_CMD_LINK_BRING_DOWN) 548 return true; 549 else 550 return false; 551 } 552 553 static inline bool cgx_event_is_linkevent(u64 event) 554 { 555 if (FIELD_GET(EVTREG_ID, event) == CGX_EVT_LINK_CHANGE) 556 return true; 557 else 558 return false; 559 } 560 561 static inline int cgx_fwi_get_mkex_prfl_sz(u64 *prfl_sz, 562 struct cgx *cgx) 563 { 564 u64 req = 0; 565 u64 resp; 566 int err; 567 568 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_SIZE, req); 569 err = cgx_fwi_cmd_generic(req, &resp, cgx, 0); 570 if (!err) 571 *prfl_sz = FIELD_GET(RESP_MKEX_PRFL_SIZE, resp); 572 573 return err; 574 } 575 576 static inline int cgx_fwi_get_mkex_prfl_addr(u64 *prfl_addr, 577 struct cgx *cgx) 578 { 579 u64 req = 0; 580 u64 resp; 581 int err; 582 583 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_ADDR, req); 584 err = cgx_fwi_cmd_generic(req, &resp, cgx, 0); 585 if (!err) 586 *prfl_addr = FIELD_GET(RESP_MKEX_PRFL_ADDR, resp); 587 588 return err; 589 } 590 591 int cgx_get_mkex_prfl_info(u64 *addr, u64 *size) 592 { 593 struct cgx *cgx_dev; 594 int err; 595 596 if (!addr || !size) 597 return -EINVAL; 598 599 cgx_dev = list_first_entry(&cgx_list, struct cgx, cgx_list); 600 if (!cgx_dev) 601 return -ENXIO; 602 603 err = cgx_fwi_get_mkex_prfl_sz(size, cgx_dev); 604 if (err) 605 return -EIO; 606 607 err = cgx_fwi_get_mkex_prfl_addr(addr, cgx_dev); 608 if (err) 609 return -EIO; 610 611 return 0; 612 } 613 EXPORT_SYMBOL(cgx_get_mkex_prfl_info); 614 615 static irqreturn_t cgx_fwi_event_handler(int irq, void *data) 616 { 617 struct lmac *lmac = data; 618 struct cgx *cgx; 619 u64 event; 620 621 cgx = lmac->cgx; 622 623 event = cgx_read(cgx, lmac->lmac_id, CGX_EVENT_REG); 624 625 if (!FIELD_GET(EVTREG_ACK, event)) 626 return IRQ_NONE; 627 628 switch (FIELD_GET(EVTREG_EVT_TYPE, event)) { 629 case CGX_EVT_CMD_RESP: 630 /* Copy the response. Since only one command is active at a 631 * time, there is no way a response can get overwritten 632 */ 633 lmac->resp = event; 634 /* Ensure response is updated before thread context starts */ 635 smp_wmb(); 636 637 /* There wont be separate events for link change initiated from 638 * software; Hence report the command responses as events 639 */ 640 if (cgx_cmdresp_is_linkevent(event)) 641 cgx_link_change_handler(event, lmac); 642 643 /* Release thread waiting for completion */ 644 lmac->cmd_pend = false; 645 wake_up_interruptible(&lmac->wq_cmd_cmplt); 646 break; 647 case CGX_EVT_ASYNC: 648 if (cgx_event_is_linkevent(event)) 649 cgx_link_change_handler(event, lmac); 650 break; 651 } 652 653 /* Any new event or command response will be posted by firmware 654 * only after the current status is acked. 655 * Ack the interrupt register as well. 656 */ 657 cgx_write(lmac->cgx, lmac->lmac_id, CGX_EVENT_REG, 0); 658 cgx_write(lmac->cgx, lmac->lmac_id, CGXX_CMRX_INT, FW_CGX_INT); 659 660 return IRQ_HANDLED; 661 } 662 663 /* APIs for PHY management using CGX firmware interface */ 664 665 /* callback registration for hardware events like link change */ 666 int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id) 667 { 668 struct cgx *cgx = cgxd; 669 struct lmac *lmac; 670 671 lmac = lmac_pdata(lmac_id, cgx); 672 if (!lmac) 673 return -ENODEV; 674 675 lmac->event_cb = *cb; 676 677 return 0; 678 } 679 EXPORT_SYMBOL(cgx_lmac_evh_register); 680 681 int cgx_lmac_evh_unregister(void *cgxd, int lmac_id) 682 { 683 struct lmac *lmac; 684 unsigned long flags; 685 struct cgx *cgx = cgxd; 686 687 lmac = lmac_pdata(lmac_id, cgx); 688 if (!lmac) 689 return -ENODEV; 690 691 spin_lock_irqsave(&lmac->event_cb_lock, flags); 692 lmac->event_cb.notify_link_chg = NULL; 693 lmac->event_cb.data = NULL; 694 spin_unlock_irqrestore(&lmac->event_cb_lock, flags); 695 696 return 0; 697 } 698 EXPORT_SYMBOL(cgx_lmac_evh_unregister); 699 700 static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable) 701 { 702 u64 req = 0; 703 u64 resp; 704 705 if (enable) 706 req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_UP, req); 707 else 708 req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_DOWN, req); 709 710 return cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id); 711 } 712 713 static inline int cgx_fwi_read_version(u64 *resp, struct cgx *cgx) 714 { 715 u64 req = 0; 716 717 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_FW_VER, req); 718 return cgx_fwi_cmd_generic(req, resp, cgx, 0); 719 } 720 721 static int cgx_lmac_verify_fwi_version(struct cgx *cgx) 722 { 723 struct device *dev = &cgx->pdev->dev; 724 int major_ver, minor_ver; 725 u64 resp; 726 int err; 727 728 if (!cgx->lmac_count) 729 return 0; 730 731 err = cgx_fwi_read_version(&resp, cgx); 732 if (err) 733 return err; 734 735 major_ver = FIELD_GET(RESP_MAJOR_VER, resp); 736 minor_ver = FIELD_GET(RESP_MINOR_VER, resp); 737 dev_dbg(dev, "Firmware command interface version = %d.%d\n", 738 major_ver, minor_ver); 739 if (major_ver != CGX_FIRMWARE_MAJOR_VER || 740 minor_ver != CGX_FIRMWARE_MINOR_VER) 741 return -EIO; 742 else 743 return 0; 744 } 745 746 static void cgx_lmac_linkup_work(struct work_struct *work) 747 { 748 struct cgx *cgx = container_of(work, struct cgx, cgx_cmd_work); 749 struct device *dev = &cgx->pdev->dev; 750 int i, err; 751 752 /* Do Link up for all the lmacs */ 753 for (i = 0; i < cgx->lmac_count; i++) { 754 err = cgx_fwi_link_change(cgx, i, true); 755 if (err) 756 dev_info(dev, "cgx port %d:%d Link up command failed\n", 757 cgx->cgx_id, i); 758 } 759 } 760 761 int cgx_lmac_linkup_start(void *cgxd) 762 { 763 struct cgx *cgx = cgxd; 764 765 if (!cgx) 766 return -ENODEV; 767 768 queue_work(cgx->cgx_cmd_workq, &cgx->cgx_cmd_work); 769 770 return 0; 771 } 772 EXPORT_SYMBOL(cgx_lmac_linkup_start); 773 774 static int cgx_lmac_init(struct cgx *cgx) 775 { 776 struct lmac *lmac; 777 int i, err; 778 779 cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMRX_RX_LMACS) & 0x7; 780 if (cgx->lmac_count > MAX_LMAC_PER_CGX) 781 cgx->lmac_count = MAX_LMAC_PER_CGX; 782 783 for (i = 0; i < cgx->lmac_count; i++) { 784 lmac = kcalloc(1, sizeof(struct lmac), GFP_KERNEL); 785 if (!lmac) 786 return -ENOMEM; 787 lmac->name = kcalloc(1, sizeof("cgx_fwi_xxx_yyy"), GFP_KERNEL); 788 if (!lmac->name) 789 return -ENOMEM; 790 sprintf(lmac->name, "cgx_fwi_%d_%d", cgx->cgx_id, i); 791 lmac->lmac_id = i; 792 lmac->cgx = cgx; 793 init_waitqueue_head(&lmac->wq_cmd_cmplt); 794 mutex_init(&lmac->cmd_lock); 795 spin_lock_init(&lmac->event_cb_lock); 796 err = request_irq(pci_irq_vector(cgx->pdev, 797 CGX_LMAC_FWI + i * 9), 798 cgx_fwi_event_handler, 0, lmac->name, lmac); 799 if (err) 800 return err; 801 802 /* Enable interrupt */ 803 cgx_write(cgx, lmac->lmac_id, CGXX_CMRX_INT_ENA_W1S, 804 FW_CGX_INT); 805 806 /* Add reference */ 807 cgx->lmac_idmap[i] = lmac; 808 } 809 810 return cgx_lmac_verify_fwi_version(cgx); 811 } 812 813 static int cgx_lmac_exit(struct cgx *cgx) 814 { 815 struct lmac *lmac; 816 int i; 817 818 if (cgx->cgx_cmd_workq) { 819 flush_workqueue(cgx->cgx_cmd_workq); 820 destroy_workqueue(cgx->cgx_cmd_workq); 821 cgx->cgx_cmd_workq = NULL; 822 } 823 824 /* Free all lmac related resources */ 825 for (i = 0; i < cgx->lmac_count; i++) { 826 lmac = cgx->lmac_idmap[i]; 827 if (!lmac) 828 continue; 829 free_irq(pci_irq_vector(cgx->pdev, CGX_LMAC_FWI + i * 9), lmac); 830 kfree(lmac->name); 831 kfree(lmac); 832 } 833 834 return 0; 835 } 836 837 static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) 838 { 839 struct device *dev = &pdev->dev; 840 struct cgx *cgx; 841 int err, nvec; 842 843 cgx = devm_kzalloc(dev, sizeof(*cgx), GFP_KERNEL); 844 if (!cgx) 845 return -ENOMEM; 846 cgx->pdev = pdev; 847 848 pci_set_drvdata(pdev, cgx); 849 850 err = pci_enable_device(pdev); 851 if (err) { 852 dev_err(dev, "Failed to enable PCI device\n"); 853 pci_set_drvdata(pdev, NULL); 854 return err; 855 } 856 857 err = pci_request_regions(pdev, DRV_NAME); 858 if (err) { 859 dev_err(dev, "PCI request regions failed 0x%x\n", err); 860 goto err_disable_device; 861 } 862 863 /* MAP configuration registers */ 864 cgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); 865 if (!cgx->reg_base) { 866 dev_err(dev, "CGX: Cannot map CSR memory space, aborting\n"); 867 err = -ENOMEM; 868 goto err_release_regions; 869 } 870 871 nvec = CGX_NVEC; 872 err = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX); 873 if (err < 0 || err != nvec) { 874 dev_err(dev, "Request for %d msix vectors failed, err %d\n", 875 nvec, err); 876 goto err_release_regions; 877 } 878 879 cgx->cgx_id = (pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM) >> 24) 880 & CGX_ID_MASK; 881 882 /* init wq for processing linkup requests */ 883 INIT_WORK(&cgx->cgx_cmd_work, cgx_lmac_linkup_work); 884 cgx->cgx_cmd_workq = alloc_workqueue("cgx_cmd_workq", 0, 0); 885 if (!cgx->cgx_cmd_workq) { 886 dev_err(dev, "alloc workqueue failed for cgx cmd"); 887 err = -ENOMEM; 888 goto err_free_irq_vectors; 889 } 890 891 list_add(&cgx->cgx_list, &cgx_list); 892 893 cgx_link_usertable_init(); 894 895 err = cgx_lmac_init(cgx); 896 if (err) 897 goto err_release_lmac; 898 899 return 0; 900 901 err_release_lmac: 902 cgx_lmac_exit(cgx); 903 list_del(&cgx->cgx_list); 904 err_free_irq_vectors: 905 pci_free_irq_vectors(pdev); 906 err_release_regions: 907 pci_release_regions(pdev); 908 err_disable_device: 909 pci_disable_device(pdev); 910 pci_set_drvdata(pdev, NULL); 911 return err; 912 } 913 914 static void cgx_remove(struct pci_dev *pdev) 915 { 916 struct cgx *cgx = pci_get_drvdata(pdev); 917 918 cgx_lmac_exit(cgx); 919 list_del(&cgx->cgx_list); 920 pci_free_irq_vectors(pdev); 921 pci_release_regions(pdev); 922 pci_disable_device(pdev); 923 pci_set_drvdata(pdev, NULL); 924 } 925 926 struct pci_driver cgx_driver = { 927 .name = DRV_NAME, 928 .id_table = cgx_id_table, 929 .probe = cgx_probe, 930 .remove = cgx_remove, 931 }; 932