cregit-Linux how code gets into the kernel

Release 4.14 drivers/firewire/ohci.c

Directory: drivers/firewire
/*
 * Driver for OHCI 1394 controllers
 *
 * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>

#include <asm/byteorder.h>
#include <asm/page.h>

#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
#endif

#include "core.h"
#include "ohci.h"


#define ohci_info(ohci, f, args...)	dev_info(ohci->card.device, f, ##args)

#define ohci_notice(ohci, f, args...)	dev_notice(ohci->card.device, f, ##args)

#define ohci_err(ohci, f, args...)	dev_err(ohci->card.device, f, ##args)


#define DESCRIPTOR_OUTPUT_MORE		0

#define DESCRIPTOR_OUTPUT_LAST		(1 << 12)

#define DESCRIPTOR_INPUT_MORE		(2 << 12)

#define DESCRIPTOR_INPUT_LAST		(3 << 12)

#define DESCRIPTOR_STATUS		(1 << 11)

#define DESCRIPTOR_KEY_IMMEDIATE	(2 << 8)

#define DESCRIPTOR_PING			(1 << 7)

#define DESCRIPTOR_YY			(1 << 6)

#define DESCRIPTOR_NO_IRQ		(0 << 4)

#define DESCRIPTOR_IRQ_ERROR		(1 << 4)

#define DESCRIPTOR_IRQ_ALWAYS		(3 << 4)

#define DESCRIPTOR_BRANCH_ALWAYS	(3 << 2)

#define DESCRIPTOR_WAIT			(3 << 0)


#define DESCRIPTOR_CMD			(0xf << 12)


struct descriptor {
	
__le16 req_count;
	
__le16 control;
	
__le32 data_address;
	
__le32 branch_address;
	
__le16 res_count;
	
__le16 transfer_status;
} __attribute__((aligned(16)));


#define CONTROL_SET(regs)	(regs)

#define CONTROL_CLEAR(regs)	((regs) + 4)

#define COMMAND_PTR(regs)	((regs) + 12)

#define CONTEXT_MATCH(regs)	((regs) + 16)


#define AR_BUFFER_SIZE	(32*1024)

#define AR_BUFFERS_MIN	DIV_ROUND_UP(AR_BUFFER_SIZE, PAGE_SIZE)
/* we need at least two pages for proper list management */

#define AR_BUFFERS	(AR_BUFFERS_MIN >= 2 ? AR_BUFFERS_MIN : 2)


#define MAX_ASYNC_PAYLOAD	4096

#define MAX_AR_PACKET_SIZE	(16 + MAX_ASYNC_PAYLOAD + 4)

#define AR_WRAPAROUND_PAGES	DIV_ROUND_UP(MAX_AR_PACKET_SIZE, PAGE_SIZE)


struct ar_context {
	
struct fw_ohci *ohci;
	
struct page *pages[AR_BUFFERS];
	
void *buffer;
	
struct descriptor *descriptors;
	
dma_addr_t descriptors_bus;
	
void *pointer;
	
unsigned int last_buffer_index;
	
u32 regs;
	
struct tasklet_struct tasklet;
};

struct context;


typedef int (*descriptor_callback_t)(struct context *ctx,
				     struct descriptor *d,
				     struct descriptor *last);

/*
 * A buffer that contains a block of DMA-able coherent memory used for
 * storing a portion of a DMA descriptor program.
 */

struct descriptor_buffer {
	
struct list_head list;
	
dma_addr_t buffer_bus;
	
size_t buffer_size;
	
size_t used;
	
struct descriptor buffer[0];
};


struct context {
	
struct fw_ohci *ohci;
	
u32 regs;
	
int total_allocation;
	
u32 current_bus;
	
bool running;
	
bool flushing;

	/*
         * List of page-sized buffers for storing DMA descriptors.
         * Head of list contains buffers in use and tail of list contains
         * free buffers.
         */
	
struct list_head buffer_list;

	/*
         * Pointer to a buffer inside buffer_list that contains the tail
         * end of the current DMA program.
         */
	
struct descriptor_buffer *buffer_tail;

	/*
         * The descriptor containing the branch address of the first
         * descriptor that has not yet been filled by the device.
         */
	
struct descriptor *last;

	/*
         * The last descriptor block in the DMA program. It contains the branch
         * address that must be updated upon appending a new descriptor.
         */
	
struct descriptor *prev;
	
int prev_z;

	
descriptor_callback_t callback;

	
struct tasklet_struct tasklet;
};


#define IT_HEADER_SY(v)          ((v) <<  0)

#define IT_HEADER_TCODE(v)       ((v) <<  4)

#define IT_HEADER_CHANNEL(v)     ((v) <<  8)

#define IT_HEADER_TAG(v)         ((v) << 14)

#define IT_HEADER_SPEED(v)       ((v) << 16)

#define IT_HEADER_DATA_LENGTH(v) ((v) << 16)


struct iso_context {
	
struct fw_iso_context base;
	
struct context context;
	
void *header;
	
size_t header_length;
	
unsigned long flushing_completions;
	
u32 mc_buffer_bus;
	
u16 mc_completed;
	
u16 last_timestamp;
	
u8 sync;
	
u8 tags;
};


#define CONFIG_ROM_SIZE 1024


struct fw_ohci {
	
struct fw_card card;

	
__iomem char *registers;
	
int node_id;
	
int generation;
	
int request_generation;	/* for timestamping incoming requests */
	
unsigned quirks;
	
unsigned int pri_req_max;
	
u32 bus_time;
	
bool bus_time_running;
	
bool is_root;
	
bool csr_state_setclear_abdicate;
	
int n_ir;
	
int n_it;
	/*
         * Spinlock for accessing fw_ohci data.  Never call out of
         * this driver with this lock held.
         */
	
spinlock_t lock;

	
struct mutex phy_reg_mutex;

	
void *misc_buffer;
	
dma_addr_t misc_buffer_bus;

	
struct ar_context ar_request_ctx;
	
struct ar_context ar_response_ctx;
	
struct context at_request_ctx;
	
struct context at_response_ctx;

	
u32 it_context_support;
	
u32 it_context_mask;     /* unoccupied IT contexts */
	
struct iso_context *it_context_list;
	
u64 ir_context_channels; /* unoccupied channels */
	
u32 ir_context_support;
	
u32 ir_context_mask;     /* unoccupied IR contexts */
	
struct iso_context *ir_context_list;
	
u64 mc_channels; /* channels in use by the multichannel IR context */
	
bool mc_allocated;

	
__be32    *config_rom;
	
dma_addr_t config_rom_bus;
	
__be32    *next_config_rom;
	
dma_addr_t next_config_rom_bus;
	
__be32     next_header;

	
__le32    *self_id;
	
dma_addr_t self_id_bus;
	
struct work_struct bus_reset_work;

	
u32 self_id_buffer[512];
};


static struct workqueue_struct *selfid_workqueue;


static inline struct fw_ohci *fw_ohci(struct fw_card *card) { return container_of(card, struct fw_ohci, card); }

Contributors

PersonTokensPropCommitsCommitProp
Kristian Högsberg1768.00%133.33%
Stefan Richter728.00%133.33%
Adrian Bunk14.00%133.33%
Total25100.00%3100.00%

#define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 #define IR_CONTEXT_BUFFER_FILL 0x80000000 #define IR_CONTEXT_ISOCH_HEADER 0x40000000 #define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000 #define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000 #define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000 #define CONTEXT_RUN 0x8000 #define CONTEXT_WAKE 0x1000 #define CONTEXT_DEAD 0x0800 #define CONTEXT_ACTIVE 0x0400 #define OHCI1394_MAX_AT_REQ_RETRIES 0xf #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 #define OHCI1394_REGISTER_SIZE 0x800 #define OHCI1394_PCI_HCI_Control 0x40 #define SELF_ID_BUF_SIZE 0x800 #define OHCI_TCODE_PHY_PACKET 0x0e #define OHCI_VERSION_1_1 0x010010 static char ohci_driver_name[] = KBUILD_MODNAME; #define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd #define PCI_DEVICE_ID_AGERE_FW643 0x5901 #define PCI_DEVICE_ID_CREATIVE_SB1394 0x4001 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 #define PCI_DEVICE_ID_TI_TSB12LV26 0x8020 #define PCI_DEVICE_ID_TI_TSB82AA2 0x8025 #define PCI_DEVICE_ID_VIA_VT630X 0x3044 #define PCI_REV_ID_VIA_VT6306 0x46 #define PCI_DEVICE_ID_VIA_VT6315 0x3403 #define QUIRK_CYCLE_TIMER 0x1 #define QUIRK_RESET_PACKET 0x2 #define QUIRK_BE_HEADERS 0x4 #define QUIRK_NO_1394A 0x8 #define QUIRK_NO_MSI 0x10 #define QUIRK_TI_SLLZ059 0x20 #define QUIRK_IR_WAKE 0x40 /* In case of multiple matches in ohci_quirks[], only the first one is used. */ static const struct { unsigned short vendor, device, revision, flags; } ohci_quirks[] = { {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID, QUIRK_BE_HEADERS}, {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, QUIRK_NO_MSI}, {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, QUIRK_NO_MSI}, {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID, QUIRK_NO_MSI}, {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV26, PCI_ANY_ID, QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB82AA2, PCI_ANY_ID, QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT630X, PCI_REV_ID_VIA_VT6306, QUIRK_CYCLE_TIMER | QUIRK_IR_WAKE}, {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, 0, QUIRK_CYCLE_TIMER /* FIXME: necessary? */ | QUIRK_NO_MSI}, {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, PCI_ANY_ID, QUIRK_NO_MSI}, {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, }; /* This overrides anything that was found in ohci_quirks[]. */ static int param_quirks; module_param_named(quirks, param_quirks, int, 0644); MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" ", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER) ", reset packet generation = " __stringify(QUIRK_RESET_PACKET) ", AR/selfID endianness = " __stringify(QUIRK_BE_HEADERS) ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A) ", disable MSI = " __stringify(QUIRK_NO_MSI) ", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059) ", IR wake unreliable = " __stringify(QUIRK_IR_WAKE) ")"); #define OHCI_PARAM_DEBUG_AT_AR 1 #define OHCI_PARAM_DEBUG_SELFIDS 2 #define OHCI_PARAM_DEBUG_IRQS 4 #define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */ static int param_debug; module_param_named(debug, param_debug, int, 0644); MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); static bool param_remote_dma; module_param_named(remote_dma, param_remote_dma, bool, 0444); MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)");
static void log_irqs(struct fw_ohci *ohci, u32 evt) { if (likely(!(param_debug & (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS)))) return; if (!(param_debug & OHCI_PARAM_DEBUG_IRQS) && !(evt & OHCI1394_busReset)) return; ohci_notice(ohci, "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", evt & OHCI1394_RSPkt ? " AR_resp" : "", evt & OHCI1394_reqTxComplete ? " AT_req" : "", evt & OHCI1394_respTxComplete ? " AT_resp" : "", evt & OHCI1394_isochRx ? " IR" : "", evt & OHCI1394_isochTx ? " IT" : "", evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "", evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "", evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", evt & OHCI1394_regAccessFail ? " regAccessFail" : "", evt & OHCI1394_unrecoverableError ? " unrecoverableError" : "", evt & OHCI1394_busReset ? " busReset" : "", evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds | OHCI1394_cycleInconsistent | OHCI1394_regAccessFail | OHCI1394_busReset) ? " ?" : ""); }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter17183.82%444.44%
Clemens Ladisch199.31%222.22%
Jay Fenlason104.90%111.11%
Jarod Wilson31.47%111.11%
Peter Hurley10.49%111.11%
Total204100.00%9100.00%

static const char *speed[] = { [0] = "S100", [1] = "S200", [2] = "S400", [3] = "beta", }; static const char *power[] = { [0] = "+0W", [1] = "+15W", [2] = "+30W", [3] = "+45W", [4] = "-3W", [5] = " ?W", [6] = "-3..-6W", [7] = "-3..-10W", }; static const char port[] = { '.', '-', 'p', 'c', };
static char _p(u32 *s, int shift) { return port[*s >> shift & 3]; }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter24100.00%1100.00%
Total24100.00%1100.00%


static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) { u32 *s; if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; ohci_notice(ohci, "%d selfIDs, generation %d, local node ID %04x\n", self_id_count, generation, ohci->node_id); for (s = ohci->self_id_buffer; self_id_count--; ++s) if ((*s & 1 << 23) == 0) ohci_notice(ohci, "selfID 0: %08x, phy %d [%c%c%c] %s gc=%d %s %s%s%s\n", *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), speed[*s >> 14 & 3], *s >> 16 & 63, power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); else ohci_notice(ohci, "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", *s, *s >> 24 & 63, _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2)); }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter24298.37%480.00%
Peter Hurley41.63%120.00%
Total246100.00%5100.00%

static const char *evts[] = { [0x00] = "evt_no_status", [0x01] = "-reserved-", [0x02] = "evt_long_packet", [0x03] = "evt_missing_ack", [0x04] = "evt_underrun", [0x05] = "evt_overrun", [0x06] = "evt_descriptor_read", [0x07] = "evt_data_read", [0x08] = "evt_data_write", [0x09] = "evt_bus_reset", [0x0a] = "evt_timeout", [0x0b] = "evt_tcode_err", [0x0c] = "-reserved-", [0x0d] = "-reserved-", [0x0e] = "evt_unknown", [0x0f] = "evt_flushed", [0x10] = "-reserved-", [0x11] = "ack_complete", [0x12] = "ack_pending ", [0x13] = "-reserved-", [0x14] = "ack_busy_X", [0x15] = "ack_busy_A", [0x16] = "ack_busy_B", [0x17] = "-reserved-", [0x18] = "-reserved-", [0x19] = "-reserved-", [0x1a] = "-reserved-", [0x1b] = "ack_tardy", [0x1c] = "-reserved-", [0x1d] = "ack_data_error", [0x1e] = "ack_type_error", [0x1f] = "-reserved-", [0x20] = "pending/cancelled", }; static const char *tcodes[] = { [0x0] = "QW req", [0x1] = "BW req", [0x2] = "W resp", [0x3] = "-reserved-", [0x4] = "QR req", [0x5] = "BR req", [0x6] = "QR resp", [0x7] = "BR resp", [0x8] = "cycle start", [0x9] = "Lk req", [0xa] = "async stream packet", [0xb] = "Lk resp", [0xc] = "-reserved-", [0xd] = "-reserved-", [0xe] = "link internal", [0xf] = "-reserved-", };
static void log_ar_at_event(struct fw_ohci *ohci, char dir, int speed, u32 *header, int evt) { int tcode = header[0] >> 4 & 0xf; char specific[12]; if (likely(!(param_debug & OHCI_PARAM_DEBUG_AT_AR))) return; if (unlikely(evt >= ARRAY_SIZE(evts))) evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n", dir, (header[2] >> 16) & 0xff); return; } switch (tcode) { case 0x0: case 0x6: case 0x8: snprintf(specific, sizeof(specific), " = %08x", be32_to_cpu((__force __be32)header[3])); break; case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: snprintf(specific, sizeof(specific), " %x,%x", header[3] >> 16, header[3] & 0xffff); break; default: specific[0] = '\0'; } switch (tcode) { case 0xa: ohci_notice(ohci, "A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); break; case 0xe: ohci_notice(ohci, "A%c %s, PHY %08x %08x\n", dir, evts[evt], header[1], header[2]); break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %04x%08x%s\n", dir, speed, header[0] >> 10 & 0x3f, header[1] >> 16, header[0] >> 16, evts[evt], tcodes[tcode], header[1] & 0xffff, header[2], specific); break; default: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s%s\n", dir, speed, header[0] >> 10 & 0x3f, header[1] >> 16, header[0] >> 16, evts[evt], tcodes[tcode], specific); } }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter33390.49%350.00%
Clemens Ladisch256.79%116.67%
Peter Hurley71.90%116.67%
Kristian Högsberg30.82%116.67%
Total368100.00%6100.00%


static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data) { writel(data, ohci->registers + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Kristian Högsberg2996.67%150.00%
Adrian Bunk13.33%150.00%
Total30100.00%2100.00%


static inline u32 reg_read(const struct fw_ohci *ohci, int offset) { return readl(ohci->registers + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Kristian Högsberg2596.15%150.00%
Adrian Bunk13.85%150.00%
Total26100.00%2100.00%


static inline void flush_writes(const struct fw_ohci *ohci) { /* Do a dummy read to flush writes. */ reg_read(ohci, OHCI1394_Version); }

Contributors

PersonTokensPropCommitsCommitProp
Kristian Högsberg2095.24%150.00%
Adrian Bunk14.76%150.00%
Total21100.00%2100.00%

/* * 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; int i; 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); /* * Try a few times without waiting. Sleeping is necessary * only when the link/PHY interface is busy. */ if (i >= 3) msleep(1); } ohci_err(ohci, "failed to read phy reg %d\n", addr); dump_stack(); return -EBUSY; }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter5954.13%444.44%
Kristian Högsberg3229.36%111.11%
Clemens Ladisch1110.09%222.22%
Peter Hurley76.42%222.22%
Total109100.00%9100.00%


static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val) { int i; reg_write(ohci, OHCI1394_PhyControl, 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; if (i >= 3) msleep(1); } ohci_err(ohci, "failed to write phy reg %d, val %u\n", addr, val); dump_stack(); return -EBUSY; }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Richter6860.18%342.86%
Kristian Högsberg2824.78%114.29%
Peter Hurley97.96%228.57%
Clemens Ladisch87.08%114.29%
Total113100.00%7100.00%


static int update_phy_reg(struct fw_ohci *ohci, int addr, int clear_bits, int set_bits) { int ret = read_phy_reg(ohci, addr); if (ret < 0) return ret; /* * The interrupt status bits are cleared by writing a one bit. * Avoid clearing them unless explicitly requested in set_bits. */ if (addr == 5) clear_bits |= PHY_INT_STATUS_BITS; return write_phy_reg(ohci, addr, (ret & ~clear_bits) | set_bits); }

Contributors

PersonTokensPropCommitsCommitProp
Clemens Ladisch3856.72%233.33%
Stefan Richter1522.39%233.33%
Kristian Högsberg1420.90%233.33%
Total67100.00%6100.00%


static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr) { int ret; ret = update_phy_reg(ohci, 7, PHY_PAGE_SELECT, page << 5); if (ret < 0) return ret; return read_phy_reg(ohci, addr); }

Contributors

PersonTokensPropCommitsCommitProp
Clemens Ladisch3465.38%125.00%
Kristian Högsberg1019.23%125.00%
Stefan Richter815.38%250.00%
Total52100.00%4100.00%


static int ohci_read_phy_reg(struct fw_card *card, int addr) { struct fw_ohci *ohci = fw_ohci(card); int ret; mutex_lock(&ohci->phy_reg_mutex); ret = read_phy_reg(ohci,