diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
| -rw-r--r-- | drivers/firewire/ohci.c | 48 | 
1 files changed, 33 insertions, 15 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 438e6c83117..bcf792fac44 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -253,7 +253,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)  #define OHCI1394_MAX_PHYS_RESP_RETRIES	0x8  #define OHCI1394_REGISTER_SIZE		0x800 -#define OHCI_LOOP_COUNT			500  #define OHCI1394_PCI_HCI_Control	0x40  #define SELF_ID_BUF_SIZE		0x800  #define OHCI_TCODE_PHY_PACKET		0x0e @@ -264,6 +263,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME;  #define PCI_DEVICE_ID_AGERE_FW643	0x5901  #define PCI_DEVICE_ID_JMICRON_JMB38X_FW	0x2380  #define PCI_DEVICE_ID_TI_TSB12LV22	0x8009 +#define PCI_VENDOR_ID_PINNACLE_SYSTEMS	0x11bd  #define QUIRK_CYCLE_TIMER		1  #define QUIRK_RESET_PACKET		2 @@ -513,6 +513,12 @@ static inline void flush_writes(const struct fw_ohci *ohci)  	reg_read(ohci, OHCI1394_Version);  } +/* + * Beware!  read_phy_reg(), write_phy_reg(), update_phy_reg(), and + * read_paged_phy_reg() require the caller to hold ohci->phy_reg_mutex. + * In other words, only use ohci_read_phy_reg() and ohci_update_phy_reg() + * directly.  Exceptions are intrinsically serialized contexts like pci_probe. + */  static int read_phy_reg(struct fw_ohci *ohci, int addr)  {  	u32 val; @@ -521,6 +527,9 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr)  	reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));  	for (i = 0; i < 3 + 100; i++) {  		val = reg_read(ohci, OHCI1394_PhyControl); +		if (!~val) +			return -ENODEV; /* Card was ejected. */ +  		if (val & OHCI1394_PhyControl_ReadDone)  			return OHCI1394_PhyControl_ReadData(val); @@ -544,6 +553,9 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)  		  OHCI1394_PhyControl_Write(addr, val));  	for (i = 0; i < 3 + 100; i++) {  		val = reg_read(ohci, OHCI1394_PhyControl); +		if (!~val) +			return -ENODEV; /* Card was ejected. */ +  		if (!(val & OHCI1394_PhyControl_WritePending))  			return 0; @@ -629,7 +641,6 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index)  	ctx->last_buffer_index = index;  	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); -	flush_writes(ctx->ohci);  }  static void ar_context_release(struct ar_context *ctx) @@ -1001,7 +1012,6 @@ static void ar_context_run(struct ar_context *ctx)  	reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1);  	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); -	flush_writes(ctx->ohci);  }  static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) @@ -1201,14 +1211,14 @@ static void context_stop(struct context *ctx)  	reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);  	ctx->running = false; -	flush_writes(ctx->ohci); -	for (i = 0; i < 10; i++) { +	for (i = 0; i < 1000; i++) {  		reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));  		if ((reg & CONTEXT_ACTIVE) == 0)  			return; -		mdelay(1); +		if (i) +			udelay(10);  	}  	fw_error("Error: DMA context still active (0x%08x)\n", reg);  } @@ -1345,12 +1355,10 @@ static int at_context_queue_packet(struct context *ctx,  	context_append(ctx, d, z, 4 - z); -	if (ctx->running) { +	if (ctx->running)  		reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); -		flush_writes(ohci); -	} else { +	else  		context_run(ctx, 0); -	}  	return 0;  } @@ -1959,14 +1967,18 @@ static irqreturn_t irq_handler(int irq, void *data)  static int software_reset(struct fw_ohci *ohci)  { +	u32 val;  	int i;  	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); +	for (i = 0; i < 500; i++) { +		val = reg_read(ohci, OHCI1394_HCControlSet); +		if (!~val) +			return -ENODEV; /* Card was ejected. */ -	for (i = 0; i < OHCI_LOOP_COUNT; i++) { -		if ((reg_read(ohci, OHCI1394_HCControlSet) & -		     OHCI1394_HCControl_softReset) == 0) +		if (!(val & OHCI1394_HCControl_softReset))  			return 0; +  		msleep(1);  	} @@ -2196,7 +2208,9 @@ static int ohci_enable(struct fw_card *card,  		  OHCI1394_LinkControl_rcvPhyPkt);  	ar_context_run(&ohci->ar_request_ctx); -	ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */ +	ar_context_run(&ohci->ar_response_ctx); + +	flush_writes(ohci);  	/* We are ready to go, reset bus to finish initialization. */  	fw_schedule_bus_reset(&ohci->card, false, true); @@ -3128,7 +3142,6 @@ static void ohci_flush_queue_iso(struct fw_iso_context *base)  			&container_of(base, struct iso_context, base)->context;  	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); -	flush_writes(ctx->ohci);  }  static const struct fw_card_driver ohci_driver = { @@ -3190,6 +3203,11 @@ static int __devinit pci_probe(struct pci_dev *dev,  	int i, err;  	size_t size; +	if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) { +		dev_err(&dev->dev, "Pinnacle MovieBoard is not yet supported\n"); +		return -ENOSYS; +	} +  	ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);  	if (ohci == NULL) {  		err = -ENOMEM;  |