diff options
Diffstat (limited to 'drivers/nvme/host/apple.c')
| -rw-r--r-- | drivers/nvme/host/apple.c | 326 |
1 files changed, 223 insertions, 103 deletions
diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index b317ce6c4ec3..15b3d07f8ccd 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -35,7 +35,6 @@ #include "nvme.h" #define APPLE_ANS_BOOT_TIMEOUT USEC_PER_SEC -#define APPLE_ANS_MAX_QUEUE_DEPTH 64 #define APPLE_ANS_COPROC_CPU_CONTROL 0x44 #define APPLE_ANS_COPROC_CPU_CONTROL_RUN BIT(4) @@ -75,6 +74,8 @@ #define APPLE_NVME_AQ_DEPTH 2 #define APPLE_NVME_AQ_MQ_TAG_DEPTH (APPLE_NVME_AQ_DEPTH - 1) +#define APPLE_NVME_IOSQES 7 + /* * These can be higher, but we need to ensure that any command doesn't * require an sg allocation that needs more than a page of data. @@ -142,6 +143,7 @@ struct apple_nvme_queue { u32 __iomem *sq_db; u32 __iomem *cq_db; + u16 sq_tail; u16 cq_head; u8 cq_phase; @@ -166,11 +168,17 @@ struct apple_nvme_iod { struct scatterlist *sg; }; +struct apple_nvme_hw { + bool has_lsq_nvmmu; + u32 max_queue_depth; +}; + struct apple_nvme { struct device *dev; void __iomem *mmio_coproc; void __iomem *mmio_nvme; + const struct apple_nvme_hw *hw; struct device **pd_dev; struct device_link **pd_link; @@ -209,19 +217,21 @@ static inline struct apple_nvme *queue_to_apple_nvme(struct apple_nvme_queue *q) { if (q->is_adminq) return container_of(q, struct apple_nvme, adminq); - else - return container_of(q, struct apple_nvme, ioq); + + return container_of(q, struct apple_nvme, ioq); } static unsigned int apple_nvme_queue_depth(struct apple_nvme_queue *q) { - if (q->is_adminq) + struct apple_nvme *anv = queue_to_apple_nvme(q); + + if (q->is_adminq && anv->hw->has_lsq_nvmmu) return APPLE_NVME_AQ_DEPTH; - else - return APPLE_ANS_MAX_QUEUE_DEPTH; + + return anv->hw->max_queue_depth; } -static void apple_nvme_rtkit_crashed(void *cookie) +static void apple_nvme_rtkit_crashed(void *cookie, const void *crashlog, size_t crashlog_size) { struct apple_nvme *anv = cookie; @@ -280,7 +290,28 @@ static void apple_nvmmu_inval(struct apple_nvme_queue *q, unsigned int tag) "NVMMU TCB invalidation failed\n"); } -static void apple_nvme_submit_cmd(struct apple_nvme_queue *q, +static void apple_nvme_submit_cmd_t8015(struct apple_nvme_queue *q, + struct nvme_command *cmd) +{ + struct apple_nvme *anv = queue_to_apple_nvme(q); + + spin_lock_irq(&anv->lock); + + if (q->is_adminq) + memcpy(&q->sqes[q->sq_tail], cmd, sizeof(*cmd)); + else + memcpy((void *)q->sqes + (q->sq_tail << APPLE_NVME_IOSQES), + cmd, sizeof(*cmd)); + + if (++q->sq_tail == anv->hw->max_queue_depth) + q->sq_tail = 0; + + writel(q->sq_tail, q->sq_db); + spin_unlock_irq(&anv->lock); +} + + +static void apple_nvme_submit_cmd_t8103(struct apple_nvme_queue *q, struct nvme_command *cmd) { struct apple_nvme *anv = queue_to_apple_nvme(q); @@ -301,8 +332,8 @@ static void apple_nvme_submit_cmd(struct apple_nvme_queue *q, memcpy(&q->sqes[tag], cmd, sizeof(*cmd)); /* - * This lock here doesn't make much sense at a first glace but - * removing it will result in occasional missed completetion + * This lock here doesn't make much sense at a first glance but + * removing it will result in occasional missed completion * interrupts even though the commands still appear on the CQ. * It's unclear why this happens but our best guess is that * there is a bug in the firmware triggered when a new command @@ -525,7 +556,7 @@ static blk_status_t apple_nvme_map_data(struct apple_nvme *anv, if (!iod->sg) return BLK_STS_RESOURCE; sg_init_table(iod->sg, blk_rq_nr_phys_segments(req)); - iod->nents = blk_rq_map_sg(req->q, req, iod->sg); + iod->nents = blk_rq_map_sg(req, iod->sg); if (!iod->nents) goto out_free_sg; @@ -590,7 +621,8 @@ static inline void apple_nvme_handle_cqe(struct apple_nvme_queue *q, __u16 command_id = READ_ONCE(cqe->command_id); struct request *req; - apple_nvmmu_inval(q, command_id); + if (anv->hw->has_lsq_nvmmu) + apple_nvmmu_inval(q, command_id); req = nvme_find_rq(apple_nvme_queue_tagset(anv, q), command_id); if (unlikely(!req)) { @@ -599,7 +631,8 @@ static inline void apple_nvme_handle_cqe(struct apple_nvme_queue *q, } if (!nvme_try_complete_req(req, cqe->status, cqe->result) && - !blk_mq_add_to_batch(req, iob, nvme_req(req)->status, + !blk_mq_add_to_batch(req, iob, + nvme_req(req)->status != NVME_SC_SUCCESS, apple_nvme_complete_batch)) apple_nvme_complete_rq(req); } @@ -649,7 +682,7 @@ static bool apple_nvme_handle_cq(struct apple_nvme_queue *q, bool force) found = apple_nvme_poll_cq(q, &iob); - if (!rq_list_empty(iob.req_list)) + if (!rq_list_empty(&iob.req_list)) apple_nvme_complete_batch(&iob); return found; @@ -684,7 +717,7 @@ static int apple_nvme_create_cq(struct apple_nvme *anv) c.create_cq.opcode = nvme_admin_create_cq; c.create_cq.prp1 = cpu_to_le64(anv->ioq.cq_dma_addr); c.create_cq.cqid = cpu_to_le16(1); - c.create_cq.qsize = cpu_to_le16(APPLE_ANS_MAX_QUEUE_DEPTH - 1); + c.create_cq.qsize = cpu_to_le16(anv->hw->max_queue_depth - 1); c.create_cq.cq_flags = cpu_to_le16(NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED); c.create_cq.irq_vector = cpu_to_le16(0); @@ -712,7 +745,7 @@ static int apple_nvme_create_sq(struct apple_nvme *anv) c.create_sq.opcode = nvme_admin_create_sq; c.create_sq.prp1 = cpu_to_le64(anv->ioq.sq_dma_addr); c.create_sq.sqid = cpu_to_le16(1); - c.create_sq.qsize = cpu_to_le16(APPLE_ANS_MAX_QUEUE_DEPTH - 1); + c.create_sq.qsize = cpu_to_le16(anv->hw->max_queue_depth - 1); c.create_sq.sq_flags = cpu_to_le16(NVME_QUEUE_PHYS_CONTIG); c.create_sq.cqid = cpu_to_le16(1); @@ -764,7 +797,12 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx, } nvme_start_request(req); - apple_nvme_submit_cmd(q, cmnd); + + if (anv->hw->has_lsq_nvmmu) + apple_nvme_submit_cmd_t8103(q, cmnd); + else + apple_nvme_submit_cmd_t8015(q, cmnd); + return BLK_STS_OK; out_free_cmd: @@ -797,6 +835,7 @@ static int apple_nvme_init_request(struct blk_mq_tag_set *set, static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown) { + enum nvme_ctrl_state state = nvme_ctrl_state(&anv->ctrl); u32 csts = readl(anv->mmio_nvme + NVME_REG_CSTS); bool dead = false, freeze = false; unsigned long flags; @@ -808,8 +847,8 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown) if (csts & NVME_CSTS_CFS) dead = true; - if (anv->ctrl.state == NVME_CTRL_LIVE || - anv->ctrl.state == NVME_CTRL_RESETTING) { + if (state == NVME_CTRL_LIVE || + state == NVME_CTRL_RESETTING) { freeze = true; nvme_start_freeze(&anv->ctrl); } @@ -881,7 +920,7 @@ static enum blk_eh_timer_return apple_nvme_timeout(struct request *req) unsigned long flags; u32 csts = readl(anv->mmio_nvme + NVME_REG_CSTS); - if (anv->ctrl.state != NVME_CTRL_LIVE) { + if (nvme_ctrl_state(&anv->ctrl) != NVME_CTRL_LIVE) { /* * From rdma.c: * If we are resetting, connecting or deleting we should @@ -968,11 +1007,13 @@ static const struct blk_mq_ops apple_nvme_mq_ops = { static void apple_nvme_init_queue(struct apple_nvme_queue *q) { unsigned int depth = apple_nvme_queue_depth(q); + struct apple_nvme *anv = queue_to_apple_nvme(q); q->cq_head = 0; q->cq_phase = 1; - memset(q->tcbs, 0, - APPLE_ANS_MAX_QUEUE_DEPTH * sizeof(struct apple_nvmmu_tcb)); + if (anv->hw->has_lsq_nvmmu) + memset(q->tcbs, 0, anv->hw->max_queue_depth + * sizeof(struct apple_nvmmu_tcb)); memset(q->cqes, 0, depth * sizeof(struct nvme_completion)); WRITE_ONCE(q->enabled, true); wmb(); /* ensure the first interrupt sees the initialization */ @@ -985,10 +1026,10 @@ static void apple_nvme_reset_work(struct work_struct *work) u32 boot_status, aqa; struct apple_nvme *anv = container_of(work, struct apple_nvme, ctrl.reset_work); + enum nvme_ctrl_state state = nvme_ctrl_state(&anv->ctrl); - if (anv->ctrl.state != NVME_CTRL_RESETTING) { - dev_warn(anv->dev, "ctrl state %d is not RESETTING\n", - anv->ctrl.state); + if (state != NVME_CTRL_RESETTING) { + dev_warn(anv->dev, "ctrl state %d is not RESETTING\n", state); ret = -ENODEV; goto out; } @@ -1010,25 +1051,37 @@ static void apple_nvme_reset_work(struct work_struct *work) ret = apple_rtkit_shutdown(anv->rtk); if (ret) goto out; + + writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); } - writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + /* + * Only do the soft-reset if the CPU is not running, which means either we + * or the previous stage shut it down cleanly. + */ + if (!(readl(anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL) & + APPLE_ANS_COPROC_CPU_CONTROL_RUN)) { - ret = reset_control_assert(anv->reset); - if (ret) - goto out; + ret = reset_control_assert(anv->reset); + if (ret) + goto out; - ret = apple_rtkit_reinit(anv->rtk); - if (ret) - goto out; + ret = apple_rtkit_reinit(anv->rtk); + if (ret) + goto out; - ret = reset_control_deassert(anv->reset); - if (ret) - goto out; + ret = reset_control_deassert(anv->reset); + if (ret) + goto out; + + writel(APPLE_ANS_COPROC_CPU_CONTROL_RUN, + anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + + ret = apple_rtkit_boot(anv->rtk); + } else { + ret = apple_rtkit_wake(anv->rtk); + } - writel(APPLE_ANS_COPROC_CPU_CONTROL_RUN, - anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); - ret = apple_rtkit_boot(anv->rtk); if (ret) { dev_err(anv->dev, "ANS did not boot"); goto out; @@ -1055,49 +1108,55 @@ static void apple_nvme_reset_work(struct work_struct *work) dma_set_max_seg_size(anv->dev, 0xffffffff); - /* - * Enable NVMMU and linear submission queues. - * While we could keep those disabled and pretend this is slightly - * more common NVMe controller we'd still need some quirks (e.g. - * sq entries will be 128 bytes) and Apple might drop support for - * that mode in the future. - */ - writel(APPLE_ANS_LINEAR_SQ_EN, - anv->mmio_nvme + APPLE_ANS_LINEAR_SQ_CTRL); + if (anv->hw->has_lsq_nvmmu) { + /* + * Enable NVMMU and linear submission queues which is required + * since T6000. + */ + writel(APPLE_ANS_LINEAR_SQ_EN, + anv->mmio_nvme + APPLE_ANS_LINEAR_SQ_CTRL); - /* Allow as many pending command as possible for both queues */ - writel(APPLE_ANS_MAX_QUEUE_DEPTH | (APPLE_ANS_MAX_QUEUE_DEPTH << 16), - anv->mmio_nvme + APPLE_ANS_MAX_PEND_CMDS_CTRL); + /* Allow as many pending command as possible for both queues */ + writel(anv->hw->max_queue_depth + | (anv->hw->max_queue_depth << 16), anv->mmio_nvme + + APPLE_ANS_MAX_PEND_CMDS_CTRL); - /* Setup the NVMMU for the maximum admin and IO queue depth */ - writel(APPLE_ANS_MAX_QUEUE_DEPTH - 1, - anv->mmio_nvme + APPLE_NVMMU_NUM_TCBS); + /* Setup the NVMMU for the maximum admin and IO queue depth */ + writel(anv->hw->max_queue_depth - 1, + anv->mmio_nvme + APPLE_NVMMU_NUM_TCBS); - /* - * This is probably a chicken bit: without it all commands where any PRP - * is set to zero (including those that don't use that field) fail and - * the co-processor complains about "completed with err BAD_CMD-" or - * a "NULL_PRP_PTR_ERR" in the syslog - */ - writel(readl(anv->mmio_nvme + APPLE_ANS_UNKNOWN_CTRL) & - ~APPLE_ANS_PRP_NULL_CHECK, - anv->mmio_nvme + APPLE_ANS_UNKNOWN_CTRL); + /* + * This is probably a chicken bit: without it all commands + * where any PRP is set to zero (including those that don't use + * that field) fail and the co-processor complains about + * "completed with err BAD_CMD-" or a "NULL_PRP_PTR_ERR" in the + * syslog + */ + writel(readl(anv->mmio_nvme + APPLE_ANS_UNKNOWN_CTRL) & + ~APPLE_ANS_PRP_NULL_CHECK, + anv->mmio_nvme + APPLE_ANS_UNKNOWN_CTRL); + } /* Setup the admin queue */ - aqa = APPLE_NVME_AQ_DEPTH - 1; + if (anv->hw->has_lsq_nvmmu) + aqa = APPLE_NVME_AQ_DEPTH - 1; + else + aqa = anv->hw->max_queue_depth - 1; aqa |= aqa << 16; writel(aqa, anv->mmio_nvme + NVME_REG_AQA); writeq(anv->adminq.sq_dma_addr, anv->mmio_nvme + NVME_REG_ASQ); writeq(anv->adminq.cq_dma_addr, anv->mmio_nvme + NVME_REG_ACQ); - /* Setup NVMMU for both queues */ - writeq(anv->adminq.tcb_dma_addr, - anv->mmio_nvme + APPLE_NVMMU_ASQ_TCB_BASE); - writeq(anv->ioq.tcb_dma_addr, - anv->mmio_nvme + APPLE_NVMMU_IOSQ_TCB_BASE); + if (anv->hw->has_lsq_nvmmu) { + /* Setup NVMMU for both queues */ + writeq(anv->adminq.tcb_dma_addr, + anv->mmio_nvme + APPLE_NVMMU_ASQ_TCB_BASE); + writeq(anv->ioq.tcb_dma_addr, + anv->mmio_nvme + APPLE_NVMMU_IOSQ_TCB_BASE); + } anv->ctrl.sqsize = - APPLE_ANS_MAX_QUEUE_DEPTH - 1; /* 0's based queue depth */ + anv->hw->max_queue_depth - 1; /* 0's based queue depth */ anv->ctrl.cap = readq(anv->mmio_nvme + NVME_REG_CAP); dev_dbg(anv->dev, "Enabling controller now"); @@ -1224,6 +1283,7 @@ static const struct nvme_ctrl_ops nvme_ctrl_ops = { .reg_read64 = apple_nvme_reg_read64, .free_ctrl = apple_nvme_free_ctrl, .get_address = apple_nvme_get_address, + .get_virt_boundary = nvme_get_virt_boundary, }; static void apple_nvme_async_probe(void *data, async_cookie_t cookie) @@ -1250,7 +1310,6 @@ static int apple_nvme_alloc_tagsets(struct apple_nvme *anv) anv->admin_tagset.timeout = NVME_ADMIN_TIMEOUT; anv->admin_tagset.numa_node = NUMA_NO_NODE; anv->admin_tagset.cmd_size = sizeof(struct apple_nvme_iod); - anv->admin_tagset.flags = BLK_MQ_F_NO_SCHED; anv->admin_tagset.driver_data = &anv->adminq; ret = blk_mq_alloc_tag_set(&anv->admin_tagset); @@ -1269,12 +1328,12 @@ static int apple_nvme_alloc_tagsets(struct apple_nvme *anv) * both queues. The admin queue gets the first APPLE_NVME_AQ_DEPTH which * must be marked as reserved in the IO queue. */ - anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH; - anv->tagset.queue_depth = APPLE_ANS_MAX_QUEUE_DEPTH - 1; + if (anv->hw->has_lsq_nvmmu) + anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH; + anv->tagset.queue_depth = anv->hw->max_queue_depth - 1; anv->tagset.timeout = NVME_IO_TIMEOUT; anv->tagset.numa_node = NUMA_NO_NODE; anv->tagset.cmd_size = sizeof(struct apple_nvme_iod); - anv->tagset.flags = BLK_MQ_F_SHOULD_MERGE; anv->tagset.driver_data = &anv->ioq; ret = blk_mq_alloc_tag_set(&anv->tagset); @@ -1295,6 +1354,7 @@ static int apple_nvme_queue_alloc(struct apple_nvme *anv, struct apple_nvme_queue *q) { unsigned int depth = apple_nvme_queue_depth(q); + size_t iosq_size; q->cqes = dmam_alloc_coherent(anv->dev, depth * sizeof(struct nvme_completion), @@ -1302,22 +1362,28 @@ static int apple_nvme_queue_alloc(struct apple_nvme *anv, if (!q->cqes) return -ENOMEM; - q->sqes = dmam_alloc_coherent(anv->dev, - depth * sizeof(struct nvme_command), + if (anv->hw->has_lsq_nvmmu) + iosq_size = depth * sizeof(struct nvme_command); + else + iosq_size = depth << APPLE_NVME_IOSQES; + + q->sqes = dmam_alloc_coherent(anv->dev, iosq_size, &q->sq_dma_addr, GFP_KERNEL); if (!q->sqes) return -ENOMEM; - /* - * We need the maximum queue depth here because the NVMMU only has a - * single depth configuration shared between both queues. - */ - q->tcbs = dmam_alloc_coherent(anv->dev, - APPLE_ANS_MAX_QUEUE_DEPTH * - sizeof(struct apple_nvmmu_tcb), - &q->tcb_dma_addr, GFP_KERNEL); - if (!q->tcbs) - return -ENOMEM; + if (anv->hw->has_lsq_nvmmu) { + /* + * We need the maximum queue depth here because the NVMMU only + * has a single depth configuration shared between both queues. + */ + q->tcbs = dmam_alloc_coherent(anv->dev, + anv->hw->max_queue_depth * + sizeof(struct apple_nvmmu_tcb), + &q->tcb_dma_addr, GFP_KERNEL); + if (!q->tcbs) + return -ENOMEM; + } /* * initialize phase to make sure the allocated and empty memory @@ -1387,7 +1453,7 @@ static void devm_apple_nvme_mempool_destroy(void *data) mempool_destroy(data); } -static int apple_nvme_probe(struct platform_device *pdev) +static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct apple_nvme *anv; @@ -1395,12 +1461,18 @@ static int apple_nvme_probe(struct platform_device *pdev) anv = devm_kzalloc(dev, sizeof(*anv), GFP_KERNEL); if (!anv) - return -ENOMEM; + return ERR_PTR(-ENOMEM); anv->dev = get_device(dev); anv->adminq.is_adminq = true; platform_set_drvdata(pdev, anv); + anv->hw = of_device_get_match_data(&pdev->dev); + if (!anv->hw) { + ret = -ENODEV; + goto put_dev; + } + ret = apple_nvme_attach_genpd(anv); if (ret < 0) { dev_err_probe(dev, ret, "Failed to attach power domains"); @@ -1432,10 +1504,17 @@ static int apple_nvme_probe(struct platform_device *pdev) goto put_dev; } - anv->adminq.sq_db = anv->mmio_nvme + APPLE_ANS_LINEAR_ASQ_DB; - anv->adminq.cq_db = anv->mmio_nvme + APPLE_ANS_ACQ_DB; - anv->ioq.sq_db = anv->mmio_nvme + APPLE_ANS_LINEAR_IOSQ_DB; - anv->ioq.cq_db = anv->mmio_nvme + APPLE_ANS_IOCQ_DB; + if (anv->hw->has_lsq_nvmmu) { + anv->adminq.sq_db = anv->mmio_nvme + APPLE_ANS_LINEAR_ASQ_DB; + anv->adminq.cq_db = anv->mmio_nvme + APPLE_ANS_ACQ_DB; + anv->ioq.sq_db = anv->mmio_nvme + APPLE_ANS_LINEAR_IOSQ_DB; + anv->ioq.cq_db = anv->mmio_nvme + APPLE_ANS_IOCQ_DB; + } else { + anv->adminq.sq_db = anv->mmio_nvme + NVME_REG_DBS; + anv->adminq.cq_db = anv->mmio_nvme + APPLE_ANS_ACQ_DB; + anv->ioq.sq_db = anv->mmio_nvme + NVME_REG_DBS + 8; + anv->ioq.cq_db = anv->mmio_nvme + APPLE_ANS_IOCQ_DB; + } anv->sart = devm_apple_sart_get(dev); if (IS_ERR(anv->sart)) { @@ -1515,10 +1594,31 @@ static int apple_nvme_probe(struct platform_device *pdev) goto put_dev; } - anv->ctrl.admin_q = blk_mq_init_queue(&anv->admin_tagset); + return anv; +put_dev: + apple_nvme_detach_genpd(anv); + put_device(anv->dev); + return ERR_PTR(ret); +} + +static int apple_nvme_probe(struct platform_device *pdev) +{ + struct apple_nvme *anv; + int ret; + + anv = apple_nvme_alloc(pdev); + if (IS_ERR(anv)) + return PTR_ERR(anv); + + ret = nvme_add_ctrl(&anv->ctrl); + if (ret) + goto out_put_ctrl; + + anv->ctrl.admin_q = blk_mq_alloc_queue(&anv->admin_tagset, NULL, NULL); if (IS_ERR(anv->ctrl.admin_q)) { ret = -ENOMEM; - goto put_dev; + anv->ctrl.admin_q = NULL; + goto out_uninit_ctrl; } nvme_reset_ctrl(&anv->ctrl); @@ -1526,12 +1626,15 @@ static int apple_nvme_probe(struct platform_device *pdev) return 0; -put_dev: - put_device(anv->dev); +out_uninit_ctrl: + nvme_uninit_ctrl(&anv->ctrl); +out_put_ctrl: + nvme_put_ctrl(&anv->ctrl); + apple_nvme_detach_genpd(anv); return ret; } -static int apple_nvme_remove(struct platform_device *pdev) +static void apple_nvme_remove(struct platform_device *pdev) { struct apple_nvme *anv = platform_get_drvdata(pdev); @@ -1542,12 +1645,13 @@ static int apple_nvme_remove(struct platform_device *pdev) apple_nvme_disable(anv, true); nvme_uninit_ctrl(&anv->ctrl); - if (apple_rtkit_is_running(anv->rtk)) + if (apple_rtkit_is_running(anv->rtk)) { apple_rtkit_shutdown(anv->rtk); - apple_nvme_detach_genpd(anv); + writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + } - return 0; + apple_nvme_detach_genpd(anv); } static void apple_nvme_shutdown(struct platform_device *pdev) @@ -1555,8 +1659,11 @@ static void apple_nvme_shutdown(struct platform_device *pdev) struct apple_nvme *anv = platform_get_drvdata(pdev); apple_nvme_disable(anv, true); - if (apple_rtkit_is_running(anv->rtk)) + if (apple_rtkit_is_running(anv->rtk)) { apple_rtkit_shutdown(anv->rtk); + + writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + } } static int apple_nvme_resume(struct device *dev) @@ -1573,10 +1680,11 @@ static int apple_nvme_suspend(struct device *dev) apple_nvme_disable(anv, true); - if (apple_rtkit_is_running(anv->rtk)) + if (apple_rtkit_is_running(anv->rtk)) { ret = apple_rtkit_shutdown(anv->rtk); - writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + writel(0, anv->mmio_coproc + APPLE_ANS_COPROC_CPU_CONTROL); + } return ret; } @@ -1584,8 +1692,19 @@ static int apple_nvme_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(apple_nvme_pm_ops, apple_nvme_suspend, apple_nvme_resume); +static const struct apple_nvme_hw apple_nvme_t8015_hw = { + .has_lsq_nvmmu = false, + .max_queue_depth = 16, +}; + +static const struct apple_nvme_hw apple_nvme_t8103_hw = { + .has_lsq_nvmmu = true, + .max_queue_depth = 64, +}; + static const struct of_device_id apple_nvme_of_match[] = { - { .compatible = "apple,nvme-ans2" }, + { .compatible = "apple,t8015-nvme-ans2", .data = &apple_nvme_t8015_hw }, + { .compatible = "apple,nvme-ans2", .data = &apple_nvme_t8103_hw }, {}, }; MODULE_DEVICE_TABLE(of, apple_nvme_of_match); @@ -1603,4 +1722,5 @@ static struct platform_driver apple_nvme_driver = { module_platform_driver(apple_nvme_driver); MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); +MODULE_DESCRIPTION("Apple ANS NVM Express device driver"); MODULE_LICENSE("GPL"); |
