/* * Copyright (c) 2012 HON HAI PRECISION IND.CO.,LTD. (FOXCONN) */ #include #include #include "ep2714_def.h" extern int fwloadbin; int fc_data_rate = FC_DATA_RATE_AUTO; static int ep8324_fc_iospace_config(struct ep8324_hw_data *ha) { if (pci_request_selected_regions(ha->pdev, ha->bars, EP8324_DRIVER_NAME)) { printk(KERN_ERR "Failed to reserve PIO/MMIO regions (%s), aborting.\n", pci_name(ha->pdev)); goto iospace_error_exit; } /* Use MMIO operations for all accesses. */ if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { printk(KERN_ERR "Invalid pci I/O region size (%s).\n", pci_name(ha->pdev)); goto iospace_error_exit; } if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { printk(KERN_ERR "Invalid PCI mem region size (%s), aborting\n", pci_name(ha->pdev)); goto iospace_error_exit; } #ifndef CONFIG_LSISAS3108_ROOT_COMPLEX ha->iobase = ioremap(pci_resource_start(ha->pdev, 0), MIN_IOBASE_LEN); #else ha->iobase = ioremap(pci_resource_start(ha->pdev, 0) | 0x7000000000ULL, MIN_IOBASE_LEN); /* FIXME: LSI rootcomplex */ #endif if (!ha->iobase) { printk(KERN_ERR "Cannot remap MMIO (%s), aborting.\n", pci_name(ha->pdev)); goto iospace_error_exit; } #ifndef CONFIG_LSISAS3108_ROOT_COMPLEX ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 4), pci_resource_len(ha->pdev, 4)); #else ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 4) | 0x7000000000ULL, /* FIXME: LSI rootcomplex */ pci_resource_len(ha->pdev, 4)); #endif if (!ha->mqiobase) { printk(KERN_ERR "BAR2/region4 not enabled\n"); goto iospace_error_exit; } /* TODO: will we need mq and msix ? */ return 0; iospace_error_exit: if (ha->iobase) iounmap(ha->iobase); return (-ENOMEM); } static int ep8324_fc_pci_config(struct ep8324_hw_data *ha) { uint16_t w; pci_set_master(ha->pdev); pci_try_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); w &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* PCIe -- adjust Maximum Read Request Size (2048). */ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP)) pcie_set_readrq(ha->pdev, 2048); pci_disable_rom(ha->pdev); return 0; } static void ep8324_fc_reset_chip(struct ep8324_hw_data *ha) { unsigned long flags = 0; struct device_reg_fc __iomem *reg = &ha->iobase->fc; uint32_t cnt, d2; uint16_t wd; /* Perform RISC reset. */ spin_lock_irqsave(&ha->hardware_lock, flags); /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) break; udelay(10); } WRT_REG_DWORD(®->ctrl_status, CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); udelay(100); /* Wait for firmware to complete NVRAM accesses. */ d2 = (uint32_t) RD_REG_WORD(®->mailbox0); for (cnt = 10000 ; cnt && d2; cnt--) { udelay(5); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) { udelay(5); d2 = RD_REG_DWORD(®->ctrl_status); barrier(); } WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); RD_REG_DWORD(®->hccr); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); RD_REG_DWORD(®->hccr); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); for (cnt = 6000000 ; cnt && d2; cnt--) { udelay(5); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } spin_unlock_irqrestore(&ha->hardware_lock, flags); switch(LSW(d2)) { case FSC_ROM_READY: ha->risc_mode = RISC_ROM_MODE; break; case FSC_FW_RUNNING: ha->risc_mode = RISC_FW_MODE; break; case FSC_BOARD_ERROR: case FSC_FW_ERROR: ha->risc_mode = RISC_FW_ERROR; printk(KERN_ERR "Detect firmware error %x\n", d2); break; default: printk(KERN_ERR "Unknown firmware status %x\n", d2); break; } } static void ep8324_fc_mbx_completion(struct ep8324_hw_data *ha, uint16_t mb0) { uint16_t cnt; uint32_t mboxes; uint16_t __iomem *wptr; struct device_reg_fc __iomem *reg = &ha->iobase->fc; /* Read all mbox registers? */ mboxes = (1ULL << MAILBOX_REGISTER_COUNT) - 1; if (!ha->mcp) printk(KERN_INFO "MBX pointer ERROR.\n"); else mboxes = ha->mcp->in_mb; /* Load return mailbox registers. */ ha->flags.mbox_int = 1; ha->mailbox_out[0] = mb0; mboxes >>= 1; wptr = (uint16_t __iomem *)®->mailbox1; for (cnt = 1; cnt < MAILBOX_REGISTER_COUNT; cnt++) { if (mboxes & BIT_0) ha->mailbox_out[cnt] = RD_REG_WORD(wptr); mboxes >>= 1; wptr++; } } static void ep8324_fc_poll(struct ep8324_hw_data *ha) { struct device_reg_fc __iomem *reg; unsigned long flags; unsigned long iter; uint32_t stat; uint32_t hccr; uint16_t mb[4]; reg = &ha->iobase->fc; spin_lock_irqsave(&ha->hardware_lock, flags); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); //dprintk("POLL HOST STATUS: %08x", reg->host_status); if (stat & HSRX_RISC_PAUSED) { if (unlikely(pci_channel_offline(ha->pdev))) break; hccr = RD_REG_DWORD(®->hccr); printk(KERN_INFO "RISC paused -- HCCR=%x\n", hccr); break; } else if ((stat & HSRX_RISC_INT) == 0) break; switch (stat & 0xff) { case 0x1: case 0x2: case 0x10: case 0x11: ep8324_fc_mbx_completion(ha, MSW(stat)); break; case 0x12: mb[0] = MSW(stat); mb[1] = RD_REG_WORD(®->mailbox1); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->mailbox3); printk(KERN_DEBUG "async event %x\n", mb[0]); if (mb[0] == 0x8030) ha->flags.dcbx_int = 1; /* FIXME */ break; case 0x13: case 0x14: printk(KERN_DEBUG "Pending rsp queue event ???\n"); break; default: printk(KERN_DEBUG "Unrecognized interrupt type (%d)\n", stat * 0xff); break; } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } static int ep8324_fc_load_risc_flash(struct ep8324_hw_data *ha, uint32_t *srisc_addr, uint32_t faddr) { int ret = 0; int segments, fragment; uint32_t *dcode, dlen; uint32_t risc_addr; uint32_t risc_size; uint32_t i; segments = FA_RISC_CODE_SEGMENTS; dcode = (uint32_t *)ha->dma_buf; *srisc_addr = 0; /* Validate firmware image by checking version. */ ep8324_read_flash_data(ha, dcode, faddr + 4, 4); for (i = 0; i < 4; i++) dcode[i] = be32_to_cpu(dcode[i]); if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && dcode[3] == 0)) { printk(KERN_INFO "Unable to verify the integrity of flash firmware image.\n" "Firmware data: %08x %08x %08x %08x.\n", dcode[0], dcode[1], dcode[2], dcode[3]); return -EINVAL; } while (segments && ret == 0) { /* Read segment's load information. */ ep8324_read_flash_data(ha, dcode, faddr, 4); risc_addr = be32_to_cpu(dcode[2]); *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; risc_size = be32_to_cpu(dcode[3]); fragment = 0; while (risc_size > 0 && ret == 0) { dlen = (uint32_t)(EP8324_DMA_BUF_SIZE >> 2); if (dlen > risc_size) dlen = risc_size; ep8324_read_flash_data(ha, dcode, faddr, dlen); for (i = 0; i < dlen; i++) dcode[i] = swab32(dcode[i]); ret = ep8324_load_ram(ha, ha->dma, risc_addr, dlen); if (ret) { printk(KERN_INFO "Failed to load segment %d of firmware.\n", fragment); break; } faddr += dlen; risc_addr += dlen; risc_size -= dlen; fragment++; } /* Next segment. */ segments--; } return ret; } static int ep8324_fc_load_risc_blob(struct ep8324_hw_data *ha, uint32_t *srisc_addr) { int ret = 0; int segments, fragment; uint32_t *dcode, dlen; uint32_t risc_addr; uint32_t risc_size; uint32_t *fwcode, fwclen; uint32_t i; struct fw_blob *blob; blob = ep8324_request_firmware(ha); if (!blob) { ret = -ENODEV; goto out; } segments = FA_RISC_CODE_SEGMENTS; dcode = (uint32_t *)ha->dma_buf; *srisc_addr = 0; fwcode = (uint32_t *)blob->fw->data; fwclen = 0; /* Validate firmware image by checking version. */ if (blob->fw->size < 8 * sizeof(uint32_t)) { printk(KERN_INFO "Unable to verify integrity of firmware image (%Zd).\n", blob->fw->size); ret = -EINVAL; goto out; } for (i = 0; i < 4; i++) dcode[i] = be32_to_cpu(fwcode[i + 4]); if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && dcode[3] == 0)) { printk(KERN_INFO "Unable to verify integrity of firmware image (%Zd).\n" "Firmware data: %08x %08x %08x %08x.\n", blob->fw->size, dcode[0], dcode[1], dcode[2], dcode[3]); ret = -EINVAL; goto out; } while (segments && !ret) { risc_addr = be32_to_cpu(fwcode[2]); *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; risc_size = be32_to_cpu(fwcode[3]); /* Validate firmware image size. */ fwclen += risc_size * sizeof(uint32_t); if (blob->fw->size < fwclen) { printk(KERN_INFO "Unable to verify integrity of firmware image (%Zd).\n", blob->fw->size); ret = -EINVAL; goto out; } fragment = 0; while (risc_size > 0 && !ret) { dlen = (uint32_t)(EP8324_DMA_BUF_SIZE >> 2); if (dlen > risc_size) dlen = risc_size; for (i = 0; i < dlen; i++) dcode[i] = swab32(fwcode[i]); ret = ep8324_load_ram(ha, ha->dma, risc_addr, dlen); if (ret) { printk(KERN_INFO "Failed to load segment %d of firmware.\n", fragment); break; } fwcode += dlen; risc_addr += dlen; risc_size -= dlen; fragment++; } /* Next segment. */ segments--; } out: if (blob) ep8324_release_firmware(blob); return ret; } static int ep8324_fc_load_risc(struct ep8324_hw_data *ha, uint32_t *srisc_addr) { if (fwloadbin || !ha->flt_region_fw) return ep8324_fc_load_risc_blob(ha, srisc_addr); return ep8324_fc_load_risc_flash(ha, srisc_addr, ha->flt_region_fw); } static int ep8324_fc_init_firmware(struct ep8324_hw_data *ha) { int ret; unsigned long flags; struct device_reg_fc __iomem *ioreg = &ha->iobase->fc; struct device_reg_mq __iomem *mqreg = &ha->mqiobase->mq; struct init_cb_fc *icb; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; spin_lock_irqsave(&ha->hardware_lock, flags); /* Setup ring parameters in initialization control block. */ icb = (struct init_cb_fc *)ha->init_cb; icb->version = __constant_cpu_to_le16(FC_ICB_VERSION); icb->frame_payload_size = __constant_cpu_to_le16(2048); icb->exchange_count = __constant_cpu_to_le16(0); icb->port_name[0] = 0x21; icb->port_name[1] = 0x00 + ha->port_no; icb->port_name[2] = 0x00; icb->port_name[3] = 0xe0; icb->port_name[4] = 0x8b; icb->port_name[5] = 0x1c; icb->port_name[6] = 0x55; icb->port_name[7] = 0x86; icb->node_name[0] = 0x20; icb->node_name[1] = 0x00; icb->node_name[2] = 0x00; icb->node_name[3] = 0xe0; icb->node_name[4] = 0x8b; icb->node_name[5] = 0x1c; icb->node_name[6] = 0x55; icb->node_name[7] = 0x86; icb->login_retry_count = __constant_cpu_to_le16(8); icb->interrupt_delay_timer = __constant_cpu_to_le16(0); icb->login_timeout = __constant_cpu_to_le16(0); icb->firmware_options_1 = __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); icb->firmware_options_2 = __constant_cpu_to_le32(2 << 4); icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); icb->firmware_options_3 = __constant_cpu_to_le32(fc_data_rate << 13); icb->enode_mac[0] = 0x00; icb->enode_mac[1] = 0xC0; icb->enode_mac[2] = 0xDD; icb->enode_mac[3] = 0x04; icb->enode_mac[4] = 0x05; icb->enode_mac[5] = 0x06 + ha->port_no; icb->request_q_outpointer = __constant_cpu_to_le16(0); icb->response_q_inpointer = __constant_cpu_to_le16(0); icb->request_q_length = cpu_to_le16(QUEUE_ENTRY_CNT); icb->response_q_length = cpu_to_le16(QUEUE_ENTRY_CNT); icb->request_q_address[0] = cpu_to_le32(LSD(ha->req_q_dma)); icb->request_q_address[1] = cpu_to_le32(MSD(ha->req_q_dma)); icb->response_q_address[0] = cpu_to_le32(LSD(ha->rsp_q_dma)); icb->response_q_address[1] = cpu_to_le32(MSD(ha->rsp_q_dma)); icb->qos = __constant_cpu_to_le16(DEFAULT_QUE_QOS); icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); WRT_REG_DWORD(&mqreg->req_q_in, 0); WRT_REG_DWORD(&mqreg->req_q_out, 0); WRT_REG_DWORD(&mqreg->rsp_q_in, 0); WRT_REG_DWORD(&mqreg->rsp_q_out, 0); /* PCI posting */ RD_REG_DWORD(&ioreg->hccr); spin_unlock_irqrestore(&ha->hardware_lock, flags); memset(mcp, 0, sizeof(mbx_cmd_t)); mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; mcp->mb[1] = 0; mcp->mb[2] = MSW(ha->init_cb_dma); mcp->mb[3] = LSW(ha->init_cb_dma); mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10; mcp->in_mb = MBX_2|MBX_1|MBX_0; // 1 and 2 should normally be captured. mcp->in_mb |= MBX_3; // mb3 is additional info about the installed SFP. mcp->tov = MBX_TOV_SECONDS; ret = ep8324_mailbox_command(ha, mcp); if (!ret) ha->risc_mode = RISC_FW_MODE; else printk(KERN_INFO "Initialize firmware failed, mbs: %04x-%04x-%04x-%04x\n", mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]); dprintk("Initialize firmware, fc_data_rate = %d\n", fc_data_rate); return ret; } struct hw_operations fc_ops = { .pci_config = ep8324_fc_pci_config, .reset_chip = ep8324_fc_reset_chip, .iospace_config = ep8324_fc_iospace_config, .poll = ep8324_fc_poll, .load_risc = ep8324_fc_load_risc, .init_firmware = ep8324_fc_init_firmware, };