drivers/parisc/lba_pci.c

Source file repositories/reference/linux-study-clean/drivers/parisc/lba_pci.c

File Facts

System
Linux kernel
Corpus path
drivers/parisc/lba_pci.c
Extension
.c
Size
51917 bytes
Lines
1761
Domain
Driver Families
Bucket
drivers/parisc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if ((error_status & 0x1f) != 0) {					\
	/*								\
	 * Fail the config read request.				\
	 */								\
	error = 1;							\
	if ((error_status & LBA_FATAL_ERROR) == 0) {			\
	    /*								\
	     * Clear error status (if fatal bit not set) by setting	\
	     * clear error log bit (CL).				\
	     */								\
	    WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \
	}								\
    }									\
}

#define LBA_CFG_TR4_ADDR_SETUP(d, addr)					\
	WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR);

#define LBA_CFG_ADDR_SETUP(d, addr) {					\
    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
    /*									\
     * Read address register to ensure that LBA is the bus master,	\
     * which implies that DMA traffic has stopped when DMA arb is off.	\
     */									\
    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
}


#define LBA_CFG_RESTORE(d, base) {					\
    /*									\
     * Restore status control register (turn off clear enable).		\
     */									\
    WRITE_REG32(status_control, base + LBA_STAT_CTL);			\
    /*									\
     * Restore error config register (turn off smart mode).		\
     */									\
    WRITE_REG32(error_config, base + LBA_ERROR_CONFIG);			\
	/*								\
	 * Restore arb mask register (reenables DMA arbitration).	\
	 */								\
	WRITE_REG32(arb_mask, base + LBA_ARB_MASK);			\
}



static unsigned int
lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
{
	u32 data = ~0U;
	int error = 0;
	u32 arb_mask = 0;	/* used by LBA_CFG_SETUP/RESTORE */
	u32 error_config = 0;	/* used by LBA_CFG_SETUP/RESTORE */
	u32 status_control = 0;	/* used by LBA_CFG_SETUP/RESTORE */

	LBA_CFG_SETUP(d, tok);
	LBA_CFG_PROBE(d, tok);
	LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error);
	if (!error) {
		void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;

		LBA_CFG_ADDR_SETUP(d, tok | reg);
		switch (size) {
		case 1: data = (u32) READ_REG8(data_reg + (reg & 3)); break;
		case 2: data = (u32) READ_REG16(data_reg+ (reg & 2)); break;
		case 4: data = READ_REG32(data_reg); break;
		}
	}
	LBA_CFG_RESTORE(d, d->hba.base_addr);
	return(data);
}


static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
{
	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
	u32 tok = LBA_CFG_TOK(local_bus, devfn);
	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;

	if ((pos > 255) || (devfn > 255))
		return -EINVAL;

/* FIXME: B2K/C3600 workaround is always use old method... */
	/* if (!LBA_SKIP_PROBE(d)) */ {
		/* original - Generate config cycle on broken elroy
		  with risk we will miss PCI bus errors. */
		*data = lba_rd_cfg(d, tok, pos, size);
		DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __func__, tok, pos, *data);
		return 0;
	}

Annotation

Implementation Notes