15ef51809SAlfredo Cardigliano /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) 25ef51809SAlfredo Cardigliano * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. 35ef51809SAlfredo Cardigliano */ 45ef51809SAlfredo Cardigliano 5*23bf4ddbSAlfredo Cardigliano #include <rte_memzone.h> 6*23bf4ddbSAlfredo Cardigliano 75ef51809SAlfredo Cardigliano #include "ionic.h" 85ef51809SAlfredo Cardigliano 95ef51809SAlfredo Cardigliano static int 105ef51809SAlfredo Cardigliano ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait) 115ef51809SAlfredo Cardigliano { 125ef51809SAlfredo Cardigliano unsigned long step_msec = 100; 135ef51809SAlfredo Cardigliano unsigned int max_wait_msec = max_wait * 1000; 145ef51809SAlfredo Cardigliano unsigned long elapsed_msec = 0; 155ef51809SAlfredo Cardigliano int done; 165ef51809SAlfredo Cardigliano 175ef51809SAlfredo Cardigliano /* Wait for dev cmd to complete.. but no more than max_wait sec */ 185ef51809SAlfredo Cardigliano 195ef51809SAlfredo Cardigliano do { 205ef51809SAlfredo Cardigliano done = ionic_dev_cmd_done(idev); 215ef51809SAlfredo Cardigliano if (done) { 225ef51809SAlfredo Cardigliano IONIC_PRINT(DEBUG, "DEVCMD %d done took %ld msecs", 235ef51809SAlfredo Cardigliano idev->dev_cmd->cmd.cmd.opcode, 245ef51809SAlfredo Cardigliano elapsed_msec); 255ef51809SAlfredo Cardigliano return 0; 265ef51809SAlfredo Cardigliano } 275ef51809SAlfredo Cardigliano 285ef51809SAlfredo Cardigliano msec_delay(step_msec); 295ef51809SAlfredo Cardigliano 305ef51809SAlfredo Cardigliano elapsed_msec += step_msec; 315ef51809SAlfredo Cardigliano } while (elapsed_msec < max_wait_msec); 325ef51809SAlfredo Cardigliano 335ef51809SAlfredo Cardigliano IONIC_PRINT(DEBUG, "DEVCMD %d timeout after %ld msecs", 345ef51809SAlfredo Cardigliano idev->dev_cmd->cmd.cmd.opcode, 355ef51809SAlfredo Cardigliano elapsed_msec); 365ef51809SAlfredo Cardigliano 375ef51809SAlfredo Cardigliano return -ETIMEDOUT; 385ef51809SAlfredo Cardigliano } 395ef51809SAlfredo Cardigliano 405ef51809SAlfredo Cardigliano static int 415ef51809SAlfredo Cardigliano ionic_dev_cmd_check_error(struct ionic_dev *idev) 425ef51809SAlfredo Cardigliano { 435ef51809SAlfredo Cardigliano uint8_t status; 445ef51809SAlfredo Cardigliano 455ef51809SAlfredo Cardigliano status = ionic_dev_cmd_status(idev); 465ef51809SAlfredo Cardigliano if (status == 0) 475ef51809SAlfredo Cardigliano return 0; 485ef51809SAlfredo Cardigliano 495ef51809SAlfredo Cardigliano return -EIO; 505ef51809SAlfredo Cardigliano } 515ef51809SAlfredo Cardigliano 525ef51809SAlfredo Cardigliano int 535ef51809SAlfredo Cardigliano ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait) 545ef51809SAlfredo Cardigliano { 555ef51809SAlfredo Cardigliano int err; 565ef51809SAlfredo Cardigliano 575ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait(idev, max_wait); 585ef51809SAlfredo Cardigliano if (err) 595ef51809SAlfredo Cardigliano return err; 605ef51809SAlfredo Cardigliano 615ef51809SAlfredo Cardigliano return ionic_dev_cmd_check_error(idev); 625ef51809SAlfredo Cardigliano } 635ef51809SAlfredo Cardigliano 645ef51809SAlfredo Cardigliano int 655ef51809SAlfredo Cardigliano ionic_setup(struct ionic_adapter *adapter) 665ef51809SAlfredo Cardigliano { 675ef51809SAlfredo Cardigliano return ionic_dev_setup(adapter); 685ef51809SAlfredo Cardigliano } 695ef51809SAlfredo Cardigliano 705ef51809SAlfredo Cardigliano int 715ef51809SAlfredo Cardigliano ionic_identify(struct ionic_adapter *adapter) 725ef51809SAlfredo Cardigliano { 735ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 745ef51809SAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 755ef51809SAlfredo Cardigliano int err = 0; 765ef51809SAlfredo Cardigliano uint32_t i; 775ef51809SAlfredo Cardigliano unsigned int nwords; 785ef51809SAlfredo Cardigliano uint32_t drv_size = sizeof(ident->drv.words) / 795ef51809SAlfredo Cardigliano sizeof(ident->drv.words[0]); 805ef51809SAlfredo Cardigliano uint32_t cmd_size = sizeof(idev->dev_cmd->data) / 815ef51809SAlfredo Cardigliano sizeof(idev->dev_cmd->data[0]); 825ef51809SAlfredo Cardigliano uint32_t dev_size = sizeof(ident->dev.words) / 835ef51809SAlfredo Cardigliano sizeof(ident->dev.words[0]); 845ef51809SAlfredo Cardigliano 855ef51809SAlfredo Cardigliano memset(ident, 0, sizeof(*ident)); 865ef51809SAlfredo Cardigliano 875ef51809SAlfredo Cardigliano ident->drv.os_type = IONIC_OS_TYPE_LINUX; 885ef51809SAlfredo Cardigliano ident->drv.os_dist = 0; 895ef51809SAlfredo Cardigliano snprintf(ident->drv.os_dist_str, 905ef51809SAlfredo Cardigliano sizeof(ident->drv.os_dist_str), "Unknown"); 915ef51809SAlfredo Cardigliano ident->drv.kernel_ver = 0; 925ef51809SAlfredo Cardigliano snprintf(ident->drv.kernel_ver_str, 935ef51809SAlfredo Cardigliano sizeof(ident->drv.kernel_ver_str), "DPDK"); 945ef51809SAlfredo Cardigliano strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION, 955ef51809SAlfredo Cardigliano sizeof(ident->drv.driver_ver_str) - 1); 965ef51809SAlfredo Cardigliano 975ef51809SAlfredo Cardigliano nwords = RTE_MIN(drv_size, cmd_size); 985ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++) 995ef51809SAlfredo Cardigliano iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]); 1005ef51809SAlfredo Cardigliano 1015ef51809SAlfredo Cardigliano ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1); 1025ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 1035ef51809SAlfredo Cardigliano if (!err) { 1045ef51809SAlfredo Cardigliano nwords = RTE_MIN(dev_size, cmd_size); 1055ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++) 1065ef51809SAlfredo Cardigliano ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]); 1075ef51809SAlfredo Cardigliano } 1085ef51809SAlfredo Cardigliano 1095ef51809SAlfredo Cardigliano return err; 1105ef51809SAlfredo Cardigliano } 1115ef51809SAlfredo Cardigliano 1125ef51809SAlfredo Cardigliano int 1135ef51809SAlfredo Cardigliano ionic_init(struct ionic_adapter *adapter) 1145ef51809SAlfredo Cardigliano { 1155ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 1165ef51809SAlfredo Cardigliano int err; 1175ef51809SAlfredo Cardigliano 1185ef51809SAlfredo Cardigliano ionic_dev_cmd_init(idev); 1195ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 1205ef51809SAlfredo Cardigliano return err; 1215ef51809SAlfredo Cardigliano } 1225ef51809SAlfredo Cardigliano 1235ef51809SAlfredo Cardigliano int 1245ef51809SAlfredo Cardigliano ionic_reset(struct ionic_adapter *adapter) 1255ef51809SAlfredo Cardigliano { 1265ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 1275ef51809SAlfredo Cardigliano int err; 1285ef51809SAlfredo Cardigliano 1295ef51809SAlfredo Cardigliano ionic_dev_cmd_reset(idev); 1305ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 1315ef51809SAlfredo Cardigliano return err; 1325ef51809SAlfredo Cardigliano } 133*23bf4ddbSAlfredo Cardigliano 134*23bf4ddbSAlfredo Cardigliano int 135*23bf4ddbSAlfredo Cardigliano ionic_port_identify(struct ionic_adapter *adapter) 136*23bf4ddbSAlfredo Cardigliano { 137*23bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 138*23bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 139*23bf4ddbSAlfredo Cardigliano unsigned int port_words = sizeof(ident->port.words) / 140*23bf4ddbSAlfredo Cardigliano sizeof(ident->port.words[0]); 141*23bf4ddbSAlfredo Cardigliano unsigned int cmd_words = sizeof(idev->dev_cmd->data) / 142*23bf4ddbSAlfredo Cardigliano sizeof(idev->dev_cmd->data[0]); 143*23bf4ddbSAlfredo Cardigliano unsigned int i; 144*23bf4ddbSAlfredo Cardigliano unsigned int nwords; 145*23bf4ddbSAlfredo Cardigliano int err; 146*23bf4ddbSAlfredo Cardigliano 147*23bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_identify(idev); 148*23bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 149*23bf4ddbSAlfredo Cardigliano if (!err) { 150*23bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(port_words, cmd_words); 151*23bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++) 152*23bf4ddbSAlfredo Cardigliano ident->port.words[i] = 153*23bf4ddbSAlfredo Cardigliano ioread32(&idev->dev_cmd->data[i]); 154*23bf4ddbSAlfredo Cardigliano } 155*23bf4ddbSAlfredo Cardigliano 156*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "speed %d ", ident->port.config.speed); 157*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "mtu %d ", ident->port.config.mtu); 158*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "state %d ", ident->port.config.state); 159*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "an_enable %d ", ident->port.config.an_enable); 160*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "fec_type %d ", ident->port.config.fec_type); 161*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "pause_type %d ", ident->port.config.pause_type); 162*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "loopback_mode %d", 163*23bf4ddbSAlfredo Cardigliano ident->port.config.loopback_mode); 164*23bf4ddbSAlfredo Cardigliano 165*23bf4ddbSAlfredo Cardigliano return err; 166*23bf4ddbSAlfredo Cardigliano } 167*23bf4ddbSAlfredo Cardigliano 168*23bf4ddbSAlfredo Cardigliano static const struct rte_memzone * 169*23bf4ddbSAlfredo Cardigliano ionic_memzone_reserve(const char *name, uint32_t len, int socket_id) 170*23bf4ddbSAlfredo Cardigliano { 171*23bf4ddbSAlfredo Cardigliano const struct rte_memzone *mz; 172*23bf4ddbSAlfredo Cardigliano 173*23bf4ddbSAlfredo Cardigliano mz = rte_memzone_lookup(name); 174*23bf4ddbSAlfredo Cardigliano if (mz) 175*23bf4ddbSAlfredo Cardigliano return mz; 176*23bf4ddbSAlfredo Cardigliano 177*23bf4ddbSAlfredo Cardigliano mz = rte_memzone_reserve_aligned(name, len, socket_id, 178*23bf4ddbSAlfredo Cardigliano RTE_MEMZONE_IOVA_CONTIG, IONIC_ALIGN); 179*23bf4ddbSAlfredo Cardigliano return mz; 180*23bf4ddbSAlfredo Cardigliano } 181*23bf4ddbSAlfredo Cardigliano 182*23bf4ddbSAlfredo Cardigliano int 183*23bf4ddbSAlfredo Cardigliano ionic_port_init(struct ionic_adapter *adapter) 184*23bf4ddbSAlfredo Cardigliano { 185*23bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 186*23bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 187*23bf4ddbSAlfredo Cardigliano char z_name[RTE_MEMZONE_NAMESIZE]; 188*23bf4ddbSAlfredo Cardigliano unsigned int config_words = sizeof(ident->port.config.words) / 189*23bf4ddbSAlfredo Cardigliano sizeof(ident->port.config.words[0]); 190*23bf4ddbSAlfredo Cardigliano unsigned int cmd_words = sizeof(idev->dev_cmd->data) / 191*23bf4ddbSAlfredo Cardigliano sizeof(idev->dev_cmd->data[0]); 192*23bf4ddbSAlfredo Cardigliano unsigned int nwords; 193*23bf4ddbSAlfredo Cardigliano unsigned int i; 194*23bf4ddbSAlfredo Cardigliano int err; 195*23bf4ddbSAlfredo Cardigliano 196*23bf4ddbSAlfredo Cardigliano if (idev->port_info) 197*23bf4ddbSAlfredo Cardigliano return 0; 198*23bf4ddbSAlfredo Cardigliano 199*23bf4ddbSAlfredo Cardigliano idev->port_info_sz = RTE_ALIGN(sizeof(*idev->port_info), PAGE_SIZE); 200*23bf4ddbSAlfredo Cardigliano 201*23bf4ddbSAlfredo Cardigliano snprintf(z_name, sizeof(z_name), "%s_port_%s_info", 202*23bf4ddbSAlfredo Cardigliano IONIC_DRV_NAME, 203*23bf4ddbSAlfredo Cardigliano adapter->pci_dev->device.name); 204*23bf4ddbSAlfredo Cardigliano 205*23bf4ddbSAlfredo Cardigliano idev->port_info_z = ionic_memzone_reserve(z_name, idev->port_info_sz, 206*23bf4ddbSAlfredo Cardigliano SOCKET_ID_ANY); 207*23bf4ddbSAlfredo Cardigliano if (!idev->port_info_z) { 208*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Cannot reserve port info DMA memory"); 209*23bf4ddbSAlfredo Cardigliano return -ENOMEM; 210*23bf4ddbSAlfredo Cardigliano } 211*23bf4ddbSAlfredo Cardigliano 212*23bf4ddbSAlfredo Cardigliano idev->port_info = idev->port_info_z->addr; 213*23bf4ddbSAlfredo Cardigliano idev->port_info_pa = idev->port_info_z->iova; 214*23bf4ddbSAlfredo Cardigliano 215*23bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(config_words, cmd_words); 216*23bf4ddbSAlfredo Cardigliano 217*23bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++) 218*23bf4ddbSAlfredo Cardigliano iowrite32(ident->port.config.words[i], &idev->dev_cmd->data[i]); 219*23bf4ddbSAlfredo Cardigliano 220*23bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_init(idev); 221*23bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 222*23bf4ddbSAlfredo Cardigliano if (err) { 223*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to init port"); 224*23bf4ddbSAlfredo Cardigliano return err; 225*23bf4ddbSAlfredo Cardigliano } 226*23bf4ddbSAlfredo Cardigliano 227*23bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_UP); 228*23bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 229*23bf4ddbSAlfredo Cardigliano if (err) { 230*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(WARNING, "Failed to bring port UP"); 231*23bf4ddbSAlfredo Cardigliano return err; 232*23bf4ddbSAlfredo Cardigliano } 233*23bf4ddbSAlfredo Cardigliano 234*23bf4ddbSAlfredo Cardigliano return 0; 235*23bf4ddbSAlfredo Cardigliano } 236*23bf4ddbSAlfredo Cardigliano 237*23bf4ddbSAlfredo Cardigliano int 238*23bf4ddbSAlfredo Cardigliano ionic_port_reset(struct ionic_adapter *adapter) 239*23bf4ddbSAlfredo Cardigliano { 240*23bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 241*23bf4ddbSAlfredo Cardigliano int err; 242*23bf4ddbSAlfredo Cardigliano 243*23bf4ddbSAlfredo Cardigliano if (!idev->port_info) 244*23bf4ddbSAlfredo Cardigliano return 0; 245*23bf4ddbSAlfredo Cardigliano 246*23bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_reset(idev); 247*23bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 248*23bf4ddbSAlfredo Cardigliano if (err) { 249*23bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to reset port"); 250*23bf4ddbSAlfredo Cardigliano return err; 251*23bf4ddbSAlfredo Cardigliano } 252*23bf4ddbSAlfredo Cardigliano 253*23bf4ddbSAlfredo Cardigliano idev->port_info = NULL; 254*23bf4ddbSAlfredo Cardigliano idev->port_info_pa = 0; 255*23bf4ddbSAlfredo Cardigliano 256*23bf4ddbSAlfredo Cardigliano return 0; 257*23bf4ddbSAlfredo Cardigliano } 258