summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-10-13 21:03:13 +0200
committerChristian Brauner <brauner@kernel.org>2026-10-13 21:03:13 +0200
commit591dfa398de12e7e685bb3ec465ff3bf5cddff51 (patch)
tree159298c5e9c69109cabe0d28ad870adec31ba2aa /drivers
parent310de65e73ead75afb78379b644a025bfe0b50dd (diff)
parent290ebc69ec41e2fe26f6cee74a9efe953b08853f (diff)
downloadlinux-next-591dfa398de12e7e685bb3ec465ff3bf5cddff51.tar.gz
linux-next-591dfa398de12e7e685bb3ec465ff3bf5cddff51.zip
Merge branch 'vfs-7.4.mount' into vfs.all
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/zloop.c31
-rw-r--r--drivers/input/joystick/xpad.c4
-rw-r--r--drivers/input/misc/ati_remote2.c12
-rw-r--r--drivers/nvme/host/core.c12
-rw-r--r--drivers/nvme/target/core.c2
-rw-r--r--drivers/nvme/target/pr.c4
-rw-r--r--drivers/regulator/ltc3676.c15
-rw-r--r--drivers/regulator/of_regulator.c29
-rw-r--r--drivers/regulator/tps6594-regulator.c6
-rw-r--r--drivers/scsi/ch.c29
-rw-r--r--drivers/scsi/qedi/qedi_main.c3
-rw-r--r--drivers/spi/spi-cadence-quadspi.c3
-rw-r--r--drivers/spi/spi-nxp-fspi.c22
-rw-r--r--drivers/spi/spi-sg2044-nor.c56
-rw-r--r--drivers/ufs/core/ufs-mcq.c30
-rw-r--r--drivers/ufs/core/ufshcd.c53
-rw-r--r--drivers/ufs/host/ufs-mediatek.c18
17 files changed, 217 insertions, 112 deletions
diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index f0ca221524db..394dc2408ed7 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -800,6 +800,27 @@ static void zloop_cmd_workfn(struct work_struct *work)
current->flags = orig_flags;
}
+static void zloop_fill_zero_rq(struct request *rq, unsigned int zero_from)
+{
+ struct req_iterator iter;
+ struct bio_vec bv;
+ unsigned int pos = 0;
+ unsigned int end, off;
+
+ rq_for_each_segment(bv, rq, iter) {
+ end = pos + bv.bv_len;
+ if (end > zero_from) {
+ if (pos < zero_from)
+ off = zero_from - pos;
+ else
+ off = 0;
+ memzero_page(bv.bv_page, bv.bv_offset + off,
+ bv.bv_len - off);
+ }
+ pos = end;
+ }
+}
+
static void zloop_complete_rq(struct request *rq)
{
struct zloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
@@ -814,13 +835,9 @@ static void zloop_complete_rq(struct request *rq)
pr_err("Zone %u: failed read sector %llu, %llu sectors\n",
zone_no, cmd->sector, cmd->nr_sectors);
- if (cmd->ret >= 0 && cmd->ret != blk_rq_bytes(rq)) {
- /* short read */
- struct bio *bio;
-
- __rq_for_each_bio(bio, rq)
- zero_fill_bio(bio);
- }
+ /* Short read. Zero out the unread tail beyond cmd->ret. */
+ if (cmd->ret >= 0 && cmd->ret != blk_rq_bytes(rq))
+ zloop_fill_zero_rq(rq, cmd->ret);
break;
case REQ_OP_WRITE:
case REQ_OP_ZONE_APPEND:
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 6406ceab988a..810e52782ae8 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -302,6 +302,8 @@ static const struct xpad_device {
{ 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 },
{ 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 },
{ 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 },
+ { 0x1b1c, 0x2b1f, "Corsair Novablade Pro (Wired)", 0, XTYPE_XBOX360 },
+ { 0x1b1c, 0x2b2b, "Corsair Novablade Pro (2.4 GHz Receiver)", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
@@ -379,6 +381,7 @@ static const struct xpad_device {
{ 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
{ 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+ { 0x2dc8, 0x201e, "8BitDo Pro 2 Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 },
@@ -545,6 +548,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */
XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */
XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */
+ XPAD_XBOX360_VENDOR(0x1b1c), /* Corsair controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */
XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */
XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 8db2dca84975..3e0f874e9b16 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -672,8 +672,7 @@ static ssize_t ati_remote2_show_channel_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
return sprintf(buf, "0x%04x\n", ar2->channel_mask);
@@ -683,8 +682,7 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned int mask;
int r;
@@ -720,8 +718,7 @@ static ssize_t ati_remote2_show_mode_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
return sprintf(buf, "0x%02x\n", ar2->mode_mask);
@@ -731,8 +728,7 @@ static ssize_t ati_remote2_store_mode_mask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned int mask;
int err;
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 9bcab3dc4c11..7eb0f9fe6b18 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -598,6 +598,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
break;
case NVME_CTRL_RESETTING:
switch (old_state) {
+ case NVME_CTRL_NEW:
case NVME_CTRL_LIVE:
changed = true;
atomic_long_inc(&ctrl->nr_reset);
@@ -2616,10 +2617,19 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
nvme_mpath_revalidate_paths(ns->head);
- ret = nvme_mpath_revalidate_zones(ns->head);
unfreeze_head_queue:
blk_mq_unfreeze_queue(ns->head->disk->queue, memflags);
+
+ /*
+ * Wait until the head queue is unfrozen before revalidating
+ * its zones. blk_revalidate_disk_zones() takes the queue limits
+ * lock and then freezes the queue on its own, so it must not be
+ * called with the queue already frozen. This is also what
+ * nvme_update_ns_info_block() does for ns->disk.
+ */
+ if (!ret)
+ ret = nvme_mpath_revalidate_zones(ns->head);
}
return ret;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 8eea0a504308..07a74c2e1f58 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1325,7 +1325,7 @@ static int nvmet_req_alloc_p2pmem_sgls(struct pci_dev *p2p_dev,
return 0;
out_free_sg:
- pci_p2pmem_free_sgl(req->p2p_dev, req->sg);
+ pci_p2pmem_free_sgl(p2p_dev, req->sg);
out_err:
return -ENOMEM;
}
diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index 09d8c63f5680..81f48cb00aee 100644
--- a/drivers/nvme/target/pr.c
+++ b/drivers/nvme/target/pr.c
@@ -51,6 +51,8 @@ u16 nvmet_set_feat_resv_notif_mask(struct nvmet_req *req, u32 mask)
if (nsid != U32_MAX) {
status = nvmet_req_find_ns(req);
+ if (status == (NVME_SC_INVALID_NS | NVME_STATUS_DNR))
+ return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
if (status)
return status;
if (!req->ns->pr.enable)
@@ -75,6 +77,8 @@ u16 nvmet_get_feat_resv_notif_mask(struct nvmet_req *req)
u16 status;
status = nvmet_req_find_ns(req);
+ if (status == (NVME_SC_INVALID_NS | NVME_STATUS_DNR))
+ return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
if (status)
return status;
diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c
index 307c6f7a155d..d67cee4e0be0 100644
--- a/drivers/regulator/ltc3676.c
+++ b/drivers/regulator/ltc3676.c
@@ -232,7 +232,7 @@ static const struct regulator_desc ltc3676_regulators[LTC3676_NUM_REGULATORS] =
LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2),
};
-static bool ltc3676_readable_writeable_reg(struct device *dev, unsigned int reg)
+static bool ltc3676_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case LTC3676_BUCK1 ... LTC3676_IRQSTAT:
@@ -243,6 +243,15 @@ static bool ltc3676_readable_writeable_reg(struct device *dev, unsigned int reg)
return false;
}
+static bool ltc3676_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3676_BUCK1 ... LTC3676_IRQSTAT:
+ return true;
+ }
+ return false;
+}
+
static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -255,8 +264,8 @@ static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg)
static const struct regmap_config ltc3676_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .writeable_reg = ltc3676_readable_writeable_reg,
- .readable_reg = ltc3676_readable_writeable_reg,
+ .writeable_reg = ltc3676_writeable_reg,
+ .readable_reg = ltc3676_readable_reg,
.volatile_reg = ltc3676_volatile_reg,
.max_register = LTC3676_CLIRQ,
.use_single_read = true,
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index c0cc6cc0afd8..09e26febfc83 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -929,21 +929,26 @@ static int is_supply_name(const char *name)
* before returning to the caller, and @consumers will not be
* changed.
*
+ * On success the array is allocated here and handed to the caller, which
+ * owns it from then on: release the regulators with regulator_bulk_free()
+ * and free the array itself with kfree(). The supply names live in the
+ * same allocation, so they are gone once the array is freed.
+ *
* Return: Number of regulators on success, or a negative error number
* on failure.
*/
int of_regulator_bulk_get_all(struct device *dev, struct device_node *np,
struct regulator_bulk_data **consumers)
{
- int num_consumers = 0;
+ int num_consumers = 0, names_len = 0;
struct regulator *tmp;
struct regulator_bulk_data *_consumers = NULL;
struct property *prop;
+ char *names;
int i, n = 0, ret;
- char name[64];
/*
- * first pass: get numbers of xxx-supply
+ * first pass: get numbers of xxx-supply and the room their names take
* second pass: fill consumers
*/
restart:
@@ -953,16 +958,19 @@ restart:
continue;
if (!_consumers) {
num_consumers++;
+ names_len += i + 1;
continue;
} else {
- memcpy(name, prop->name, i);
- name[i] = '\0';
- tmp = regulator_get(dev, name);
+ memcpy(names, prop->name, i);
+ names[i] = '\0';
+ tmp = regulator_get(dev, names);
if (IS_ERR(tmp)) {
ret = PTR_ERR(tmp);
goto error;
}
+ _consumers[n].supply = names;
_consumers[n].consumer = tmp;
+ names += i + 1;
n++;
continue;
}
@@ -973,9 +981,16 @@ restart:
}
if (num_consumers == 0)
return 0;
- _consumers = kmalloc_objs(struct regulator_bulk_data, num_consumers);
+ /*
+ * The supply names are kept in the same allocation as the array, so
+ * that they share its lifetime and the caller has nothing extra to
+ * free.
+ */
+ _consumers = kzalloc(size_add(size_mul(num_consumers, sizeof(*_consumers)),
+ names_len), GFP_KERNEL);
if (!_consumers)
return -ENOMEM;
+ names = (char *)(_consumers + num_consumers);
goto restart;
error:
diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c
index 31a5218d5510..503b89a2f5f8 100644
--- a/drivers/regulator/tps6594-regulator.c
+++ b/drivers/regulator/tps6594-regulator.c
@@ -241,21 +241,21 @@ static const struct regulator_desc tps65224_buck_regs[] = {
TPS65224_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_CTRL(1),
TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges,
- 4, 0, 0, NULL, 0, 0),
+ ARRAY_SIZE(tps65224_bucks_2_3_4_ranges), 0, 0, NULL, 0, 0),
TPS6594_REGULATOR("BUCK3", "buck3", TPS6594_BUCK_3,
REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_VOUT_1(2),
TPS65224_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_CTRL(2),
TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges,
- 4, 0, 0, NULL, 0, 0),
+ ARRAY_SIZE(tps65224_bucks_2_3_4_ranges), 0, 0, NULL, 0, 0),
TPS6594_REGULATOR("BUCK4", "buck4", TPS6594_BUCK_4,
REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_VOUT_1(3),
TPS65224_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_CTRL(3),
TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges,
- 4, 0, 0, NULL, 0, 0),
+ ARRAY_SIZE(tps65224_bucks_2_3_4_ranges), 0, 0, NULL, 0, 0),
};
static const struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 4010fdbf813c..c36539c83ed1 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -112,7 +112,6 @@ typedef struct {
int minor;
char name[8];
struct scsi_device *device;
- struct scsi_device **dt; /* ptrs to data transfer elements */
u_int firsts[CH_TYPES];
u_int counts[CH_TYPES];
u_int voltags;
@@ -363,15 +362,10 @@ ch_readconfig(scsi_changer *ch)
vendor_labels[i]);
}
- /* look up the devices of the data transfer elements */
- ch->dt = kzalloc_objs(*ch->dt, ch->counts[CHET_DT]);
-
- if (!ch->dt) {
- kfree(buffer);
- return -ENOMEM;
- }
-
+ /* report the devices of the data transfer elements */
for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
+ struct scsi_device *sdev;
+
id = -1;
lun = 0;
if (elem < CH_DT_MAX && -1 != dt_id[elem]) {
@@ -387,10 +381,8 @@ ch_readconfig(scsi_changer *ch)
VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]);
if (data[6] & 0x80) {
VPRINTK(KERN_CONT, "not this SCSI bus\n");
- ch->dt[elem] = NULL;
} else if (0 == (data[6] & 0x30)) {
VPRINTK(KERN_CONT, "ID/LUN unknown\n");
- ch->dt[elem] = NULL;
} else {
id = ch->device->id;
lun = 0;
@@ -400,18 +392,16 @@ ch_readconfig(scsi_changer *ch)
}
if (-1 != id) {
VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun);
- ch->dt[elem] =
- scsi_device_lookup(ch->device->host,
- ch->device->channel,
- id,lun);
- if (!ch->dt[elem]) {
+ sdev = scsi_device_lookup(ch->device->host,
+ ch->device->channel,
+ id, lun);
+ if (!sdev) {
/* should not happen */
VPRINTK(KERN_CONT, "Huh? device not found!\n");
} else {
VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s\n",
- ch->dt[elem]->vendor,
- ch->dt[elem]->model,
- ch->dt[elem]->rev);
+ sdev->vendor, sdev->model, sdev->rev);
+ scsi_device_put(sdev);
}
}
}
@@ -575,7 +565,6 @@ static void ch_destroy(struct kref *ref)
scsi_changer *ch = container_of(ref, scsi_changer, ref);
ch->device = NULL;
- kfree(ch->dt);
kfree(ch);
}
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 227ff7bd1bdc..f394fcbb97e7 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -2652,8 +2652,6 @@ retry_probe:
snprintf(host_buf, sizeof(host_buf), "host_%d", qedi->shost->host_no);
qedi_ops->common->set_name(qedi->cdev, host_buf);
- qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi);
-
memset(&params, 0, sizeof(params));
params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
qedi->ll2_mtu = DEF_PATH_MTU;
@@ -2670,6 +2668,7 @@ retry_probe:
spin_lock_init(&qedi->task_idx_lock);
mutex_init(&qedi->stats_lock);
}
+ qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi);
qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi);
qedi_ops->ll2->start(qedi->cdev, &params);
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index ecb0be394696..5a5f1a852cbe 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1056,8 +1056,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
* care of polling the status register.
*/
if (cqspi->wr_completion) {
- reg = readl(reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
- reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL;
+ reg = CQSPI_REG_WR_DISABLE_AUTO_POLL;
writel(reg, reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
/*
* DAC mode require auto polling as flash needs to be polled
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 67d991dd249d..66cb58f95fdb 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -898,10 +898,10 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
/*
- * Per the FlexSPI reference manual (initialization sequence), MCR0 and
- * the DLL control registers should be configured while the module is in
- * stop mode (MCR0[MDIS] = 1). Enter stop mode before reconfiguring the
- * RX sample clock source and the DLL, then exit stop mode afterwards.
+ * Per the FlexSPI reference manual (initialization sequence), MCR0
+ * should be configured while the module is in stop mode (MCR0[MDIS] = 1).
+ * Enter stop mode before reconfiguring the RX sample clock source, then
+ * exit stop mode afterwards.
*/
reg = fspi_readl(f, f->iobase + FSPI_MCR0);
fspi_writel(f, reg | FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
@@ -937,6 +937,16 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
return ret;
/*
+ * Exit stop mode before running the DLL calibration. The DLL
+ * reference clock is derived from the module clock domain, which is
+ * gated while MCR0[MDIS] = 1. Calibrating the DLL in stop mode leaves
+ * the STS2 lock bits stuck at 0 (the DLL never runs), so clear MDIS
+ * first and let the module and reference clock run.
+ */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg & ~FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
+ /*
* If clock rate > 100MHz, then switch from DLL override mode to
* DLL calibration mode.
*/
@@ -945,10 +955,6 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
else
nxp_fspi_dll_override(f);
- /* Exit stop mode now that MCR0 and the DLL have been reconfigured. */
- reg = fspi_readl(f, f->iobase + FSPI_MCR0);
- fspi_writel(f, reg & ~FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
-
f->pre_op_rate = op->max_freq;
f->selected = spi_get_chipselect(spi, 0);
diff --git a/drivers/spi/spi-sg2044-nor.c b/drivers/spi/spi-sg2044-nor.c
index f3bcb8a1b92b..bc9a8ee9bce4 100644
--- a/drivers/spi/spi-sg2044-nor.c
+++ b/drivers/spi/spi-sg2044-nor.c
@@ -307,15 +307,15 @@ static ssize_t sg2044_spifmc_tran_cmd(struct sg2044_spifmc *spifmc,
return 0;
}
-static void sg2044_spifmc_trans(struct sg2044_spifmc *spifmc,
- const struct spi_mem_op *op)
+static int sg2044_spifmc_trans(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
{
if (op->data.dir == SPI_MEM_DATA_IN)
- sg2044_spifmc_read(spifmc, op);
+ return sg2044_spifmc_read(spifmc, op);
else if (op->data.dir == SPI_MEM_DATA_OUT)
- sg2044_spifmc_write(spifmc, op);
+ return sg2044_spifmc_write(spifmc, op);
else
- sg2044_spifmc_tran_cmd(spifmc, op);
+ return sg2044_spifmc_tran_cmd(spifmc, op);
}
static ssize_t sg2044_spifmc_trans_reg(struct sg2044_spifmc *spifmc,
@@ -385,29 +385,64 @@ static ssize_t sg2044_spifmc_trans_reg(struct sg2044_spifmc *spifmc,
return 0;
}
+static int sg2044_spifmc_set_speed(struct sg2044_spifmc *spifmc,
+ unsigned int speed_hz)
+{
+ unsigned long rate = clk_get_rate(spifmc->clk);
+ u64 div;
+ u32 reg;
+
+ if (!rate)
+ return -EINVAL;
+
+ /* SCK = HCLK / (2 * (SckDiv + 1)); round down the resulting SCK. */
+ div = speed_hz ? DIV_ROUND_UP_ULL(rate, 2ULL * speed_hz) : 1;
+ if (div > SPIFMC_CTRL_SCK_DIV_MASK + 1)
+ return -EINVAL;
+
+ reg = readl(spifmc->io_base + SPIFMC_CTRL);
+ reg &= ~SPIFMC_CTRL_SCK_DIV_MASK;
+ reg |= div - 1;
+ writel(reg, spifmc->io_base + SPIFMC_CTRL);
+
+ return 0;
+}
+
static int sg2044_spifmc_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct sg2044_spifmc *spifmc;
+ int ret;
spifmc = spi_controller_get_devdata(mem->spi->controller);
mutex_lock(&spifmc->lock);
+ ret = sg2044_spifmc_set_speed(spifmc, op->max_freq ?
+ min(op->max_freq, mem->spi->max_speed_hz) :
+ mem->spi->max_speed_hz);
+ if (ret)
+ goto out_unlock;
+
if (op->addr.nbytes == 0)
- sg2044_spifmc_trans_reg(spifmc, op);
+ ret = sg2044_spifmc_trans_reg(spifmc, op);
else
- sg2044_spifmc_trans(spifmc, op);
+ ret = sg2044_spifmc_trans(spifmc, op);
+out_unlock:
mutex_unlock(&spifmc->lock);
- return 0;
+ return ret;
}
static const struct spi_controller_mem_ops sg2044_spifmc_mem_ops = {
.exec_op = sg2044_spifmc_exec_op,
};
+static const struct spi_controller_mem_caps sg2044_spifmc_mem_caps = {
+ .per_op_freq = true,
+};
+
static void sg2044_spifmc_init(struct sg2044_spifmc *spifmc)
{
u32 tran_csr;
@@ -447,6 +482,10 @@ static int sg2044_spifmc_probe(struct platform_device *pdev)
if (IS_ERR(spifmc->clk))
return dev_err_probe(dev, PTR_ERR(spifmc->clk), "Cannot get and enable AHB clock\n");
+ ctrl->max_speed_hz = clk_get_rate(spifmc->clk) / 2;
+ if (!ctrl->max_speed_hz)
+ return dev_err_probe(dev, -EINVAL, "Invalid AHB clock rate\n");
+
spifmc->dev = &pdev->dev;
spifmc->ctrl = ctrl;
@@ -458,6 +497,7 @@ static int sg2044_spifmc_probe(struct platform_device *pdev)
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->auto_runtime_pm = false;
ctrl->mem_ops = &sg2044_spifmc_mem_ops;
+ ctrl->mem_caps = &sg2044_spifmc_mem_caps;
ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD;
ret = devm_mutex_init(dev, &spifmc->lock);
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index 8106d55f4041..df293b66350d 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -312,20 +312,24 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe)
UFSHCD_NUM_RESERVED;
}
+static void ufshcd_mcq_compl_cqe(struct ufs_hba *hba, struct cq_entry *cqe)
+{
+ int tag = ufshcd_mcq_get_tag(hba, cqe);
+
+ ufshcd_compl_one_cqe(hba, tag, cqe);
+ /* After processing the CQE, mark it as an empty (invalid) entry. */
+ cqe->command_desc_base_addr = 0;
+}
+
static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
struct ufs_hw_queue *hwq)
{
struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
- if (cqe->command_desc_base_addr) {
- int tag = ufshcd_mcq_get_tag(hba, cqe);
-
- ufshcd_compl_one_cqe(hba, tag, cqe);
- /* After processed the cqe, mark it empty (invalid) entry */
- cqe->command_desc_base_addr = 0;
- } else {
+ if (cqe->command_desc_base_addr)
+ ufshcd_mcq_compl_cqe(hba, cqe);
+ else
dev_err(hba->dev, "Abnormal CQ entry!\n");
- }
}
/*
@@ -333,7 +337,7 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
* controller disabled (HCE = 0). Reading host controller registers, e.g. the
* CQ tail pointer (CQTPy), may not be safe with the host controller disabled.
* Hence, iterate over all completion queue entries. This won't result in
- * double completions because ufshcd_mcq_process_cqe() clears a CQE after it
+ * double completions because ufshcd_mcq_compl_cqe() clears a CQE after it
* has been processed.
*/
void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
@@ -344,13 +348,13 @@ void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
spin_lock_irqsave(&hwq->cq_lock, flags);
while (entries > 0) {
- ufshcd_mcq_process_cqe(hba, hwq);
+ struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
+
+ if (cqe->command_desc_base_addr)
+ ufshcd_mcq_compl_cqe(hba, cqe);
ufshcd_mcq_inc_cq_head_slot(hwq);
entries--;
}
-
- ufshcd_mcq_update_cq_tail_slot(hwq);
- hwq->cq_head_slot = hwq->cq_tail_slot;
spin_unlock_irqrestore(&hwq->cq_lock, flags);
}
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 54f4e7d7de02..ca8329052cbc 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -6044,8 +6044,6 @@ static bool ufshcd_mcq_force_compl_one(struct request *rq, void *priv)
if (blk_mq_is_reserved_rq(rq) || !hwq)
return true;
- ufshcd_mcq_compl_all_cqes_lock(hba, hwq);
-
/*
* For those cmds of which the cqes are not present in the cq, complete
* them explicitly.
@@ -6061,19 +6059,6 @@ static bool ufshcd_mcq_force_compl_one(struct request *rq, void *priv)
return true;
}
-static bool ufshcd_mcq_compl_one(struct request *rq, void *priv)
-{
- struct scsi_device *sdev = rq->q->queuedata;
- struct Scsi_Host *shost = sdev->host;
- struct ufs_hba *hba = shost_priv(shost);
- struct ufs_hw_queue *hwq = ufshcd_mcq_req_to_hwq(hba, rq);
-
- if (!blk_mq_is_reserved_rq(rq) && hwq)
- ufshcd_mcq_poll_cqe_lock(hba, hwq);
-
- return true;
-}
-
/**
* ufshcd_mcq_compl_pending_transfer - MCQ mode function. It is
* invoked from the error handler context or ufshcd_host_reset_and_restore()
@@ -6088,10 +6073,18 @@ static bool ufshcd_mcq_compl_one(struct request *rq, void *priv)
static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba,
bool force_compl)
{
- blk_mq_tagset_busy_iter(&hba->host->tag_set,
- force_compl ? ufshcd_mcq_force_compl_one :
- ufshcd_mcq_compl_one,
- NULL);
+ int i;
+
+ for (i = 0; i < hba->nr_hw_queues; i++) {
+ if (force_compl)
+ ufshcd_mcq_compl_all_cqes_lock(hba, &hba->uhq[i]);
+ else
+ ufshcd_mcq_poll_cqe_lock(hba, &hba->uhq[i]);
+ }
+
+ if (force_compl)
+ blk_mq_tagset_busy_iter(&hba->host->tag_set,
+ ufshcd_mcq_force_compl_one, NULL);
}
/**
@@ -9556,6 +9549,7 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
ret = ufshcd_add_lus(hba);
out:
+ ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
if (ret)
@@ -11278,6 +11272,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
ufshcd_init_clk_gating(hba);
+ /* Released by ufshcd_async_scan(), or by out_release on failure. */
+ ufshcd_hold(hba);
+
ufshcd_init_clk_scaling(hba);
/*
@@ -11298,7 +11295,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
dev_err(hba->dev, "request irq failed\n");
- goto out_disable;
+ goto out_release;
} else {
hba->is_irq_enabled = true;
}
@@ -11314,7 +11311,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
dev_err(hba->dev, "Host controller enable failed\n");
ufshcd_print_evt_hist(hba);
ufshcd_print_host_state(hba);
- goto out_disable;
+ goto out_release;
}
INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, ufshcd_rpm_dev_flush_recheck_work);
@@ -11328,7 +11325,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
err = ufshcd_add_scsi_host(hba);
if (err)
- goto out_disable;
+ goto out_release;
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
@@ -11348,7 +11345,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
err = ufshcd_link_startup(hba);
if (err)
- goto out_disable;
+ goto out_release;
if (hba->mcq_enabled)
ufshcd_config_mcq(hba);
@@ -11365,23 +11362,23 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
/* Verify device initialization by sending NOP OUT UPIU */
err = ufshcd_verify_dev_init(hba);
if (err)
- goto out_disable;
+ goto out_release;
/* Initiate UFS initialization, and waiting until completion */
err = ufshcd_complete_dev_init(hba);
if (err)
- goto out_disable;
+ goto out_release;
err = ufshcd_device_params_init(hba);
if (err)
- goto out_disable;
+ goto out_release;
err = ufshcd_post_device_init(hba);
initialized:
ufshcd_process_probe_result(hba, probe_start, err);
if (err)
- goto out_disable;
+ goto out_release;
ufs_sysfs_add_nodes(hba->dev);
hba->dme_qos_sysfs_handle = sysfs_get_dirent(hba->dev->kobj.sd,
@@ -11392,6 +11389,8 @@ initialized:
ufshcd_pm_qos_init(hba);
return 0;
+out_release:
+ ufshcd_release(hba);
out_disable:
hba->is_irq_enabled = false;
ufshcd_hba_exit(hba);
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 814c1b7343b9..12a6d4138e44 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -509,6 +509,7 @@ static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
struct phy *mphy = host->mphy;
struct arm_smccc_res res;
+ int err;
int ret = 0;
if (!mphy || !(on ^ host->mphy_powered_on))
@@ -523,7 +524,18 @@ static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
usleep_range(200, 210);
ufs_mtk_va09_pwr_ctrl(res, 1);
}
- phy_power_on(mphy);
+ ret = phy_power_on(mphy);
+ if (ret) {
+ if (ufs_mtk_is_va09_supported(hba)) {
+ ufs_mtk_va09_pwr_ctrl(res, 0);
+ err = regulator_disable(host->reg_va09);
+ if (err)
+ dev_err(hba->dev,
+ "failed to unwind va09: %d\n", err);
+ }
+ dev_err(hba->dev, "failed to enable mphy: %d\n", ret);
+ return ret;
+ }
} else {
phy_power_off(mphy);
if (ufs_mtk_is_va09_supported(hba)) {
@@ -1295,7 +1307,9 @@ static int ufs_mtk_init(struct ufs_hba *hba)
*
* Enable phy clocks specifically here.
*/
- ufs_mtk_mphy_power_on(hba, true);
+ err = ufs_mtk_mphy_power_on(hba, true);
+ if (err)
+ goto out_variant_clear;
if (ufs_mtk_is_rtff_mtcmos(hba)) {
/* First Restore here, to avoid backup unexpected value */