Skip to content

Commit a8b661e

Browse files
kishonLorenzo Pieralisi
authored andcommitted
PCI: cadence: Convert all r/w accessors to perform only 32-bit accesses
Certain platforms like TI's J721E using Cadence PCIe IP can perform only 32-bit accesses for reading or writing to Cadence registers. Convert all read and write accesses to 32-bit in Cadence PCIe driver in preparation for adding PCIe support in TI's J721E SoC. Also add spin lock to disable interrupts while modifying PCI_STATUS register while raising legacy interrupt since PCI_STATUS is accessible by both remote RC and EP and time between read and write should be minimized. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kishon Vijay Abraham I <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent 229f587 commit a8b661e

File tree

2 files changed

+62
-18
lines changed

2 files changed

+62
-18
lines changed

drivers/pci/controller/cadence/pcie-cadence-ep.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
228228
u8 intx, bool is_asserted)
229229
{
230230
struct cdns_pcie *pcie = &ep->pcie;
231+
unsigned long flags;
231232
u32 offset;
232233
u16 status;
233234
u8 msg_code;
@@ -252,11 +253,13 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
252253
msg_code = MSG_CODE_DEASSERT_INTA + intx;
253254
}
254255

256+
spin_lock_irqsave(&ep->lock, flags);
255257
status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
256258
if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
257259
status ^= PCI_STATUS_INTERRUPT;
258260
cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
259261
}
262+
spin_unlock_irqrestore(&ep->lock, flags);
260263

261264
offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
262265
CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
@@ -464,6 +467,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
464467
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
465468
/* Reserve region 0 for IRQs */
466469
set_bit(0, &ep->ob_region_map);
470+
spin_lock_init(&ep->lock);
467471

468472
return 0;
469473

drivers/pci/controller/cadence/pcie-cadence.h

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ struct cdns_pcie_rc {
304304
* @irq_pci_fn: the latest PCI function that has updated the mapping of
305305
* the MSI/legacy IRQ dedicated outbound region.
306306
* @irq_pending: bitmask of asserted legacy IRQs.
307+
* @lock: spin lock to disable interrupts while modifying PCIe controller
308+
* registers fields (RMW) accessible by both remote RC and EP to
309+
* minimize time between read and write
307310
*/
308311
struct cdns_pcie_ep {
309312
struct cdns_pcie pcie;
@@ -315,54 +318,94 @@ struct cdns_pcie_ep {
315318
u64 irq_pci_addr;
316319
u8 irq_pci_fn;
317320
u8 irq_pending;
321+
/* protect writing to PCI_STATUS while raising legacy interrupts */
322+
spinlock_t lock;
318323
};
319324

320325

321326
/* Register access */
322-
static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
327+
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
323328
{
324-
writeb(value, pcie->reg_base + reg);
329+
writel(value, pcie->reg_base + reg);
325330
}
326331

327-
static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
332+
static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
328333
{
329-
writew(value, pcie->reg_base + reg);
334+
return readl(pcie->reg_base + reg);
330335
}
331336

332-
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
337+
static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
333338
{
334-
writel(value, pcie->reg_base + reg);
339+
void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
340+
unsigned int offset = (unsigned long)addr & 0x3;
341+
u32 val = readl(aligned_addr);
342+
343+
if (!IS_ALIGNED((uintptr_t)addr, size)) {
344+
pr_warn("Address %p and size %d are not aligned\n", addr, size);
345+
return 0;
346+
}
347+
348+
if (size > 2)
349+
return val;
350+
351+
return (val >> (8 * offset)) & ((1 << (size * 8)) - 1);
335352
}
336353

337-
static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
354+
static inline void cdns_pcie_write_sz(void __iomem *addr, int size, u32 value)
338355
{
339-
return readl(pcie->reg_base + reg);
356+
void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
357+
unsigned int offset = (unsigned long)addr & 0x3;
358+
u32 mask;
359+
u32 val;
360+
361+
if (!IS_ALIGNED((uintptr_t)addr, size)) {
362+
pr_warn("Address %p and size %d are not aligned\n", addr, size);
363+
return;
364+
}
365+
366+
if (size > 2) {
367+
writel(value, addr);
368+
return;
369+
}
370+
371+
mask = ~(((1 << (size * 8)) - 1) << (offset * 8));
372+
val = readl(aligned_addr) & mask;
373+
val |= value << (offset * 8);
374+
writel(val, aligned_addr);
340375
}
341376

342377
/* Root Port register access */
343378
static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
344379
u32 reg, u8 value)
345380
{
346-
writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
381+
void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
382+
383+
cdns_pcie_write_sz(addr, 0x1, value);
347384
}
348385

349386
static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
350387
u32 reg, u16 value)
351388
{
352-
writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
389+
void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
390+
391+
cdns_pcie_write_sz(addr, 0x2, value);
353392
}
354393

355394
/* Endpoint Function register access */
356395
static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
357396
u32 reg, u8 value)
358397
{
359-
writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
398+
void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
399+
400+
cdns_pcie_write_sz(addr, 0x1, value);
360401
}
361402

362403
static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
363404
u32 reg, u16 value)
364405
{
365-
writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
406+
void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
407+
408+
cdns_pcie_write_sz(addr, 0x2, value);
366409
}
367410

368411
static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
@@ -371,14 +414,11 @@ static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
371414
writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
372415
}
373416

374-
static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
375-
{
376-
return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
377-
}
378-
379417
static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
380418
{
381-
return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
419+
void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
420+
421+
return cdns_pcie_read_sz(addr, 0x2);
382422
}
383423

384424
static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)

0 commit comments

Comments
 (0)