Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206841
b: refs/heads/master
c: 02d37be
h: refs/heads/master
i:
  206839: f6abfde
v: v3
  • Loading branch information
Stefan Richter committed Jul 13, 2010
1 parent 9dc4749 commit cdcbf43
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 39 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8b4f70ba4967cae90d128857af1382026a24230a
refs/heads/master: 02d37bed188c500ee7afb0a2dc6b65a80704c58e
68 changes: 52 additions & 16 deletions trunk/drivers/firewire/core-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,45 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
}
EXPORT_SYMBOL(fw_core_remove_descriptor);

static int reset_bus(struct fw_card *card, bool short_reset)
{
int reg = short_reset ? 5 : 1;
int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;

return card->driver->update_phy_reg(card, reg, 0, bit);
}

void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
{
/* We don't try hard to sort out requests of long vs. short resets. */
card->br_short = short_reset;

/* Use an arbitrary short delay to combine multiple reset requests. */
fw_card_get(card);
if (!schedule_delayed_work(&card->br_work,
delayed ? DIV_ROUND_UP(HZ, 100) : 0))
fw_card_put(card);
}
EXPORT_SYMBOL(fw_schedule_bus_reset);

static void br_work(struct work_struct *work)
{
struct fw_card *card = container_of(work, struct fw_card, br_work.work);

/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
if (card->reset_jiffies != 0 &&
time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) {
if (!schedule_delayed_work(&card->br_work, 2 * HZ))
fw_card_put(card);
return;
}

fw_send_phy_config(card, FW_PHY_CONFIG_NO_NODE_ID, card->generation,
FW_PHY_CONFIG_CURRENT_GAP_COUNT);
reset_bus(card, card->br_short);
fw_card_put(card);
}

static void allocate_broadcast_channel(struct fw_card *card, int generation)
{
int channel, bandwidth = 0;
Expand All @@ -230,13 +269,13 @@ static const char gap_count_table[] = {
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
{
fw_card_get(card);
if (!schedule_delayed_work(&card->work, delay))
if (!schedule_delayed_work(&card->bm_work, delay))
fw_card_put(card);
}

static void fw_card_bm_work(struct work_struct *work)
static void bm_work(struct work_struct *work)
{
struct fw_card *card = container_of(work, struct fw_card, work.work);
struct fw_card *card = container_of(work, struct fw_card, bm_work.work);
struct fw_device *root_device;
struct fw_node *root_node;
int root_id, new_root_id, irm_id, bm_id, local_id;
Expand Down Expand Up @@ -413,7 +452,7 @@ static void fw_card_bm_work(struct work_struct *work)
fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
card->index, new_root_id, gap_count);
fw_send_phy_config(card, new_root_id, generation, gap_count);
fw_core_initiate_bus_reset(card, 1);
reset_bus(card, true);
/* Will allocate broadcast channel after the reset. */
goto out;
}
Expand Down Expand Up @@ -465,7 +504,8 @@ void fw_card_initialize(struct fw_card *card,

card->local_node = NULL;

INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
INIT_DELAYED_WORK(&card->br_work, br_work);
INIT_DELAYED_WORK(&card->bm_work, bm_work);
}
EXPORT_SYMBOL(fw_card_initialize);

Expand All @@ -491,7 +531,6 @@ int fw_card_add(struct fw_card *card,
}
EXPORT_SYMBOL(fw_card_add);


/*
* The next few functions implement a dummy driver that is used once a card
* driver shuts down an fw_card. This allows the driver to cleanly unload,
Expand All @@ -507,6 +546,11 @@ static int dummy_enable(struct fw_card *card,
return -1;
}

static int dummy_read_phy_reg(struct fw_card *card, int address)
{
return -ENODEV;
}

static int dummy_update_phy_reg(struct fw_card *card, int address,
int clear_bits, int set_bits)
{
Expand Down Expand Up @@ -547,6 +591,7 @@ static int dummy_enable_phys_dma(struct fw_card *card,

static const struct fw_card_driver dummy_driver_template = {
.enable = dummy_enable,
.read_phy_reg = dummy_read_phy_reg,
.update_phy_reg = dummy_update_phy_reg,
.set_config_rom = dummy_set_config_rom,
.send_request = dummy_send_request,
Expand All @@ -568,7 +613,7 @@ void fw_core_remove_card(struct fw_card *card)

card->driver->update_phy_reg(card, 4,
PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
fw_core_initiate_bus_reset(card, 1);
fw_schedule_bus_reset(card, false, true);

mutex_lock(&card_mutex);
list_del_init(&card->link);
Expand All @@ -588,12 +633,3 @@ void fw_core_remove_card(struct fw_card *card)
WARN_ON(!list_empty(&card->transaction_list));
}
EXPORT_SYMBOL(fw_core_remove_card);

int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
{
int reg = short_reset ? 5 : 1;
int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;

return card->driver->update_phy_reg(card, reg, 0, bit);
}
EXPORT_SYMBOL(fw_core_initiate_bus_reset);
3 changes: 2 additions & 1 deletion trunk/drivers/firewire/core-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -820,8 +820,9 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)

static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg)
{
return fw_core_initiate_bus_reset(client->device->card,
fw_schedule_bus_reset(client->device->card, true,
arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET);
return 0;
}

static void release_descriptor(struct client *client,
Expand Down
18 changes: 15 additions & 3 deletions trunk/drivers/firewire/core-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,21 @@ void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count)
{
long timeout = DIV_ROUND_UP(HZ, 10);
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
PHY_CONFIG_ROOT_ID(node_id) |
PHY_CONFIG_GAP_COUNT(gap_count);
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);

if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
data |= PHY_CONFIG_ROOT_ID(node_id);

if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
gap_count = card->driver->read_phy_reg(card, 1);
if (gap_count < 0)
return;

gap_count &= 63;
if (gap_count == 63)
return;
}
data |= PHY_CONFIG_GAP_COUNT(gap_count);

mutex_lock(&phy_config_mutex);

Expand Down
6 changes: 5 additions & 1 deletion trunk/drivers/firewire/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct fw_card_driver {
int (*enable)(struct fw_card *card,
const __be32 *config_rom, size_t length);

int (*read_phy_reg)(struct fw_card *card, int address);
int (*update_phy_reg)(struct fw_card *card, int address,
int clear_bits, int set_bits);

Expand Down Expand Up @@ -102,8 +103,8 @@ void fw_card_initialize(struct fw_card *card,
int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid);
void fw_core_remove_card(struct fw_card *card);
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
int fw_compute_block_crc(__be32 *block);
void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);

static inline struct fw_card *fw_card_get(struct fw_card *card)
Expand Down Expand Up @@ -225,6 +226,9 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
int fw_get_response_length(struct fw_request *request);
void fw_fill_response(struct fw_packet *response, u32 *request_header,
int rcode, void *payload, size_t length);

#define FW_PHY_CONFIG_NO_NODE_ID -1
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count);

Expand Down
53 changes: 38 additions & 15 deletions trunk/drivers/firewire/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#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/spinlock.h>
Expand Down Expand Up @@ -182,6 +183,8 @@ struct fw_ohci {
*/
spinlock_t lock;

struct mutex phy_reg_mutex;

struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
struct context at_request_ctx;
Expand Down Expand Up @@ -517,13 +520,10 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)
return -EBUSY;
}

static int ohci_update_phy_reg(struct fw_card *card, int addr,
int clear_bits, int set_bits)
static int update_phy_reg(struct fw_ohci *ohci, int addr,
int clear_bits, int set_bits)
{
struct fw_ohci *ohci = fw_ohci(card);
int ret;

ret = read_phy_reg(ohci, addr);
int ret = read_phy_reg(ohci, addr);
if (ret < 0)
return ret;

Expand All @@ -541,13 +541,38 @@ static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr)
{
int ret;

ret = ohci_update_phy_reg(&ohci->card, 7, PHY_PAGE_SELECT, page << 5);
ret = update_phy_reg(ohci, 7, PHY_PAGE_SELECT, page << 5);
if (ret < 0)
return ret;

return read_phy_reg(ohci, addr);
}

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, addr);
mutex_unlock(&ohci->phy_reg_mutex);

return ret;
}

static int ohci_update_phy_reg(struct fw_card *card, int addr,
int clear_bits, int set_bits)
{
struct fw_ohci *ohci = fw_ohci(card);
int ret;

mutex_lock(&ohci->phy_reg_mutex);
ret = update_phy_reg(ohci, addr, clear_bits, set_bits);
mutex_unlock(&ohci->phy_reg_mutex);

return ret;
}

static int ar_context_add_page(struct ar_context *ctx)
{
struct device *dev = ctx->ohci->card.device;
Expand Down Expand Up @@ -1676,7 +1701,7 @@ static int configure_1394a_enhancements(struct fw_ohci *ohci)
clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
set = 0;
}
ret = ohci_update_phy_reg(&ohci->card, 5, clear, set);
ret = update_phy_reg(ohci, 5, clear, set);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -1856,12 +1881,8 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_HCControl_BIBimageValid);
flush_writes(ohci);

/*
* We are ready to go, initiate bus reset to finish the
* initialization.
*/

fw_core_initiate_bus_reset(&ohci->card, 1);
/* We are ready to go, reset bus to finish initialization. */
fw_schedule_bus_reset(&ohci->card, false, true);

return 0;
}
Expand Down Expand Up @@ -1936,7 +1957,7 @@ static int ohci_set_config_rom(struct fw_card *card,
* takes effect.
*/
if (ret == 0)
fw_core_initiate_bus_reset(&ohci->card, 1);
fw_schedule_bus_reset(&ohci->card, true, true);
else
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
next_config_rom, next_config_rom_bus);
Expand Down Expand Up @@ -2570,6 +2591,7 @@ static int ohci_queue_iso(struct fw_iso_context *base,

static const struct fw_card_driver ohci_driver = {
.enable = ohci_enable,
.read_phy_reg = ohci_read_phy_reg,
.update_phy_reg = ohci_update_phy_reg,
.set_config_rom = ohci_set_config_rom,
.send_request = ohci_send_request,
Expand Down Expand Up @@ -2645,6 +2667,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
pci_set_drvdata(dev, ohci);

spin_lock_init(&ohci->lock);
mutex_init(&ohci->phy_reg_mutex);

tasklet_init(&ohci->bus_reset_tasklet,
bus_reset_tasklet, (unsigned long)ohci);
Expand Down
6 changes: 4 additions & 2 deletions trunk/include/linux/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ struct fw_card {

struct list_head link;

/* Work struct for BM duties. */
struct delayed_work work;
struct delayed_work br_work; /* bus reset job */
bool br_short;

struct delayed_work bm_work; /* bus manager job */
int bm_retries;
int bm_generation;
__be32 bm_transaction_data[2];
Expand Down

0 comments on commit cdcbf43

Please sign in to comment.