Skip to content

Commit 9d5db4e

Browse files
committed
Merge tag 'i3c/for-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: "The main change is the addition of PCI bus support for mipi-i3c-hci. I'm also carrying an hwmon patch as it makes use of the bitops addition that is then mainly used by i3c drivers. Core: - Improve initialization of numbered I2C adapters Drivers: - use parity8 helper - dw: fix possible use-after-free - mipi-i3c-hci: add support for PCI bus host - svc: many fixes for IBI and hotjoin" * tag 'i3c/for-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: master: Improve initialization of numbered I2C adapters i3c: master: Fix missing 'ret' assignment in set_speed() i3c: cdns: use parity8 helper instead of open coding it i3c: mipi-i3c-hci: use parity8 helper instead of open coding it i3c: dw: use parity8 helper instead of open coding it hwmon: (spd5118) Use generic parity calculation bitops: add generic parity calculation for u8 i3c: mipi-i3c-hci: Add support for MIPI I3C HCI on PCI bus i3c: mipi-i3c-hci: Add Intel specific quirk to ring resuming i3c: fix kdoc parameter description for module_i3c_i2c_driver() i3c: dw: Fix use-after-free in dw_i3c_master driver due to race condition
2 parents ae8b53a + 5eb6d35 commit 9d5db4e

File tree

11 files changed

+227
-34
lines changed

11 files changed

+227
-34
lines changed

drivers/hwmon/spd5118.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -291,20 +291,14 @@ static umode_t spd5118_is_visible(const void *_data, enum hwmon_sensor_types typ
291291
}
292292
}
293293

294-
static inline bool spd5118_parity8(u8 w)
295-
{
296-
w ^= w >> 4;
297-
return (0x6996 >> (w & 0xf)) & 1;
298-
}
299-
300294
/*
301295
* Bank and vendor id are 8-bit fields with seven data bits and odd parity.
302296
* Vendor IDs 0 and 0x7f are invalid.
303297
* See Jedec standard JEP106BJ for details and a list of assigned vendor IDs.
304298
*/
305299
static bool spd5118_vendor_valid(u8 bank, u8 id)
306300
{
307-
if (!spd5118_parity8(bank) || !spd5118_parity8(id))
301+
if (parity8(bank) == 0 || parity8(id) == 0)
308302
return false;
309303

310304
id &= 0x7f;

drivers/i3c/master.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
19191919
goto err_bus_cleanup;
19201920

19211921
if (master->ops->set_speed) {
1922-
master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
1922+
ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
19231923
if (ret)
19241924
goto err_bus_cleanup;
19251925
}
@@ -2486,7 +2486,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
24862486
struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
24872487
struct i2c_dev_desc *i2cdev;
24882488
struct i2c_dev_boardinfo *i2cboardinfo;
2489-
int ret;
2489+
int ret, id = -ENODEV;
24902490

24912491
adap->dev.parent = master->dev.parent;
24922492
adap->owner = master->dev.parent->driver->owner;
@@ -2497,7 +2497,15 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
24972497
adap->timeout = 1000;
24982498
adap->retries = 3;
24992499

2500-
ret = i2c_add_adapter(adap);
2500+
if (master->dev.of_node)
2501+
id = of_alias_get_id(master->dev.of_node, "i2c");
2502+
2503+
if (id >= 0) {
2504+
adap->nr = id;
2505+
ret = i2c_add_numbered_adapter(adap);
2506+
} else {
2507+
ret = i2c_add_adapter(adap);
2508+
}
25012509
if (ret)
25022510
return ret;
25032511

drivers/i3c/master/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,14 @@ config MIPI_I3C_HCI
5757

5858
This driver can also be built as a module. If so, the module will be
5959
called mipi-i3c-hci.
60+
61+
config MIPI_I3C_HCI_PCI
62+
tristate "MIPI I3C Host Controller Interface PCI support"
63+
depends on MIPI_I3C_HCI
64+
depends on PCI
65+
help
66+
Support for MIPI I3C Host Controller Interface compatible hardware
67+
on the PCI bus.
68+
69+
This driver can also be built as a module. If so, the module will be
70+
called mipi-i3c-hci-pci.

drivers/i3c/master/dw-i3c-master.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,6 @@ struct dw_i3c_i2c_dev_data {
251251
struct i3c_generic_ibi_pool *ibi_pool;
252252
};
253253

254-
static u8 even_parity(u8 p)
255-
{
256-
p ^= p >> 4;
257-
p &= 0xf;
258-
259-
return (0x9669 >> p) & 1;
260-
}
261-
262254
static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
263255
const struct i3c_ccc_cmd *cmd)
264256
{
@@ -848,7 +840,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
848840
struct dw_i3c_xfer *xfer;
849841
struct dw_i3c_cmd *cmd;
850842
u32 olddevs, newdevs;
851-
u8 p, last_addr = 0;
843+
u8 last_addr = 0;
852844
int ret, pos;
853845

854846
ret = pm_runtime_resume_and_get(master->dev);
@@ -873,9 +865,9 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
873865
}
874866

875867
master->devs[pos].addr = ret;
876-
p = even_parity(ret);
877868
last_addr = ret;
878-
ret |= (p << 7);
869+
870+
ret |= parity8(ret) ? 0 : BIT(7);
879871

880872
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret),
881873
master->regs +
@@ -1647,6 +1639,7 @@ EXPORT_SYMBOL_GPL(dw_i3c_common_probe);
16471639

16481640
void dw_i3c_common_remove(struct dw_i3c_master *master)
16491641
{
1642+
cancel_work_sync(&master->hj_work);
16501643
i3c_master_unregister(&master->base);
16511644

16521645
pm_runtime_disable(master->dev);

drivers/i3c/master/i3c-master-cdns.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,7 @@ static u32 prepare_rr0_dev_address(u32 addr)
889889
ret |= (addr & GENMASK(9, 7)) << 6;
890890

891891
/* RR0[0] = ~XOR(addr[6:0]) */
892-
if (!(hweight8(addr & 0x7f) & 1))
893-
ret |= 1;
892+
ret |= parity8(addr & 0x7f) ? 0 : BIT(0);
894893

895894
return ret;
896895
}

drivers/i3c/master/mipi-i3c-hci/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ mipi-i3c-hci-y := core.o ext_caps.o pio.o dma.o \
55
cmd_v1.o cmd_v2.o \
66
dat_v1.o dct_v1.o \
77
hci_quirks.o
8+
obj-$(CONFIG_MIPI_I3C_HCI_PCI) += mipi-i3c-hci-pci.o

drivers/i3c/master/mipi-i3c-hci/dat_v1.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,6 @@
4040
#define dat_w0_write(i, v) writel(v, hci->DAT_regs + (i) * 8)
4141
#define dat_w1_write(i, v) writel(v, hci->DAT_regs + (i) * 8 + 4)
4242

43-
static inline bool dynaddr_parity(unsigned int addr)
44-
{
45-
addr |= 1 << 7;
46-
addr += addr >> 4;
47-
addr += addr >> 2;
48-
addr += addr >> 1;
49-
return (addr & 1);
50-
}
51-
5243
static int hci_dat_v1_init(struct i3c_hci *hci)
5344
{
5445
unsigned int dat_idx;
@@ -123,7 +114,7 @@ static void hci_dat_v1_set_dynamic_addr(struct i3c_hci *hci,
123114
dat_w0 = dat_w0_read(dat_idx);
124115
dat_w0 &= ~(DAT_0_DYNAMIC_ADDRESS | DAT_0_DYNADDR_PARITY);
125116
dat_w0 |= FIELD_PREP(DAT_0_DYNAMIC_ADDRESS, address) |
126-
(dynaddr_parity(address) ? DAT_0_DYNADDR_PARITY : 0);
117+
(parity8(address) ? 0 : DAT_0_DYNADDR_PARITY);
127118
dat_w0_write(dat_idx, dat_w0);
128119
}
129120

drivers/i3c/master/mipi-i3c-hci/dma.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,9 +758,26 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
758758
complete(&rh->op_done);
759759

760760
if (status & INTR_TRANSFER_ABORT) {
761+
u32 ring_status;
762+
761763
dev_notice_ratelimited(&hci->master.dev,
762764
"ring %d: Transfer Aborted\n", i);
763765
mipi_i3c_hci_resume(hci);
766+
ring_status = rh_reg_read(RING_STATUS);
767+
if (!(ring_status & RING_STATUS_RUNNING) &&
768+
status & INTR_TRANSFER_COMPLETION &&
769+
status & INTR_TRANSFER_ERR) {
770+
/*
771+
* Ring stop followed by run is an Intel
772+
* specific required quirk after resuming the
773+
* halted controller. Do it only when the ring
774+
* is not in running state after a transfer
775+
* error.
776+
*/
777+
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
778+
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE |
779+
RING_CTRL_RUN_STOP);
780+
}
764781
}
765782
if (status & INTR_WARN_INS_STOP_MODE)
766783
dev_warn_ratelimited(&hci->master.dev,
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* PCI glue code for MIPI I3C HCI driver
4+
*
5+
* Copyright (C) 2024 Intel Corporation
6+
*
7+
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
8+
*/
9+
#include <linux/acpi.h>
10+
#include <linux/idr.h>
11+
#include <linux/kernel.h>
12+
#include <linux/module.h>
13+
#include <linux/pci.h>
14+
#include <linux/platform_device.h>
15+
16+
struct mipi_i3c_hci_pci_info {
17+
int (*init)(struct pci_dev *pci);
18+
};
19+
20+
#define INTEL_PRIV_OFFSET 0x2b0
21+
#define INTEL_PRIV_SIZE 0x28
22+
#define INTEL_PRIV_RESETS 0x04
23+
#define INTEL_PRIV_RESETS_RESET BIT(0)
24+
#define INTEL_PRIV_RESETS_RESET_DONE BIT(1)
25+
26+
static DEFINE_IDA(mipi_i3c_hci_pci_ida);
27+
28+
static int mipi_i3c_hci_pci_intel_init(struct pci_dev *pci)
29+
{
30+
unsigned long timeout;
31+
void __iomem *priv;
32+
33+
priv = devm_ioremap(&pci->dev,
34+
pci_resource_start(pci, 0) + INTEL_PRIV_OFFSET,
35+
INTEL_PRIV_SIZE);
36+
if (!priv)
37+
return -ENOMEM;
38+
39+
/* Assert reset, wait for completion and release reset */
40+
writel(0, priv + INTEL_PRIV_RESETS);
41+
timeout = jiffies + msecs_to_jiffies(10);
42+
while (!(readl(priv + INTEL_PRIV_RESETS) &
43+
INTEL_PRIV_RESETS_RESET_DONE)) {
44+
if (time_after(jiffies, timeout))
45+
break;
46+
cpu_relax();
47+
}
48+
writel(INTEL_PRIV_RESETS_RESET, priv + INTEL_PRIV_RESETS);
49+
50+
return 0;
51+
}
52+
53+
static struct mipi_i3c_hci_pci_info intel_info = {
54+
.init = mipi_i3c_hci_pci_intel_init,
55+
};
56+
57+
static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
58+
const struct pci_device_id *id)
59+
{
60+
struct mipi_i3c_hci_pci_info *info;
61+
struct platform_device *pdev;
62+
struct resource res[2];
63+
int dev_id, ret;
64+
65+
ret = pcim_enable_device(pci);
66+
if (ret)
67+
return ret;
68+
69+
pci_set_master(pci);
70+
71+
memset(&res, 0, sizeof(res));
72+
73+
res[0].flags = IORESOURCE_MEM;
74+
res[0].start = pci_resource_start(pci, 0);
75+
res[0].end = pci_resource_end(pci, 0);
76+
77+
res[1].flags = IORESOURCE_IRQ;
78+
res[1].start = pci->irq;
79+
res[1].end = pci->irq;
80+
81+
dev_id = ida_alloc(&mipi_i3c_hci_pci_ida, GFP_KERNEL);
82+
if (dev_id < 0)
83+
return dev_id;
84+
85+
pdev = platform_device_alloc("mipi-i3c-hci", dev_id);
86+
if (!pdev)
87+
return -ENOMEM;
88+
89+
pdev->dev.parent = &pci->dev;
90+
device_set_node(&pdev->dev, dev_fwnode(&pci->dev));
91+
92+
ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
93+
if (ret)
94+
goto err;
95+
96+
info = (struct mipi_i3c_hci_pci_info *)id->driver_data;
97+
if (info && info->init) {
98+
ret = info->init(pci);
99+
if (ret)
100+
goto err;
101+
}
102+
103+
ret = platform_device_add(pdev);
104+
if (ret)
105+
goto err;
106+
107+
pci_set_drvdata(pci, pdev);
108+
109+
return 0;
110+
111+
err:
112+
platform_device_put(pdev);
113+
ida_free(&mipi_i3c_hci_pci_ida, dev_id);
114+
return ret;
115+
}
116+
117+
static void mipi_i3c_hci_pci_remove(struct pci_dev *pci)
118+
{
119+
struct platform_device *pdev = pci_get_drvdata(pci);
120+
int dev_id = pdev->id;
121+
122+
platform_device_unregister(pdev);
123+
ida_free(&mipi_i3c_hci_pci_ida, dev_id);
124+
}
125+
126+
static const struct pci_device_id mipi_i3c_hci_pci_devices[] = {
127+
/* Panther Lake-H */
128+
{ PCI_VDEVICE(INTEL, 0xe37c), (kernel_ulong_t)&intel_info},
129+
{ PCI_VDEVICE(INTEL, 0xe36f), (kernel_ulong_t)&intel_info},
130+
/* Panther Lake-P */
131+
{ PCI_VDEVICE(INTEL, 0xe47c), (kernel_ulong_t)&intel_info},
132+
{ PCI_VDEVICE(INTEL, 0xe46f), (kernel_ulong_t)&intel_info},
133+
{ },
134+
};
135+
MODULE_DEVICE_TABLE(pci, mipi_i3c_hci_pci_devices);
136+
137+
static struct pci_driver mipi_i3c_hci_pci_driver = {
138+
.name = "mipi_i3c_hci_pci",
139+
.id_table = mipi_i3c_hci_pci_devices,
140+
.probe = mipi_i3c_hci_pci_probe,
141+
.remove = mipi_i3c_hci_pci_remove,
142+
};
143+
144+
module_pci_driver(mipi_i3c_hci_pci_driver);
145+
146+
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@intel.com>");
147+
MODULE_LICENSE("GPL");
148+
MODULE_DESCRIPTION("MIPI I3C HCI driver on PCI bus");

include/linux/bitops.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,37 @@ static inline int get_count_order_long(unsigned long l)
229229
return (int)fls_long(--l);
230230
}
231231

232+
/**
233+
* parity8 - get the parity of an u8 value
234+
* @value: the value to be examined
235+
*
236+
* Determine the parity of the u8 argument.
237+
*
238+
* Returns:
239+
* 0 for even parity, 1 for odd parity
240+
*
241+
* Note: This function informs you about the current parity. Example to bail
242+
* out when parity is odd:
243+
*
244+
* if (parity8(val) == 1)
245+
* return -EBADMSG;
246+
*
247+
* If you need to calculate a parity bit, you need to draw the conclusion from
248+
* this result yourself. Example to enforce odd parity, parity bit is bit 7:
249+
*
250+
* if (parity8(val) == 0)
251+
* val ^= BIT(7);
252+
*/
253+
static inline int parity8(u8 val)
254+
{
255+
/*
256+
* One explanation of this algorithm:
257+
* https://funloop.org/codex/problem/parity/README.html
258+
*/
259+
val ^= val >> 4;
260+
return (0x6996 >> (val & 0xf)) & 1;
261+
}
262+
232263
/**
233264
* __ffs64 - find first set bit in a 64 bit word
234265
* @word: The 64 bit word

0 commit comments

Comments
 (0)