forked from Minki/linux
ieee1394: support for slow links or slow 1394b phy ports
Add support for the following types of hardware: + nodes that have a link speed < PHY speed + 1394b PHYs that are less than S800 capable + 1394b/1394a adapter cable between two 1394b PHYs Also, S1600 and S3200 are now supported if IEEE1394_SPEED_MAX is raised. A probing function is added to nodemgr's config ROM fetching routine which adjusts the allowable speed if an access problem was encountered. Pros and Cons of the approach: + minimum code footprint to support this less widely used hardware + nearly no overhead for unaffected hardware - ineffective before nodemgr began to read the ROM of affected nodes - ineffective if ieee1394 is loaded with disable_nodemgr=1 The speed map CSRs which are published to the bus are not touched by the patch. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Cc: Hakan Ardo <hakan@debian.org> Cc: Calculex <linux@calculex.com> Cc: Robert J. Kosinski <robk@cmcherald.com> Signed-off-by: Ben Collins <bcollins@ubuntu.com>
This commit is contained in:
parent
57fdb58fa5
commit
647dcb5fae
@ -502,10 +502,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
|
|||||||
|
|
||||||
/* Determine speed limit */
|
/* Determine speed limit */
|
||||||
for (i = 0; i < host->node_count; i++)
|
for (i = 0; i < host->node_count; i++)
|
||||||
if (max_speed > host->speed_map[NODEID_TO_NODE(host->node_id) *
|
if (max_speed > host->speed[i])
|
||||||
64 + i])
|
max_speed = host->speed[i];
|
||||||
max_speed = host->speed_map[NODEID_TO_NODE(host->node_id) *
|
|
||||||
64 + i];
|
|
||||||
priv->bc_sspd = max_speed;
|
priv->bc_sspd = max_speed;
|
||||||
|
|
||||||
/* We'll use our maxpayload as the default mtu */
|
/* We'll use our maxpayload as the default mtu */
|
||||||
|
@ -30,12 +30,13 @@ struct hpsb_host {
|
|||||||
|
|
||||||
unsigned char iso_listen_count[64];
|
unsigned char iso_listen_count[64];
|
||||||
|
|
||||||
int node_count; /* number of identified nodes on this bus */
|
int node_count; /* number of identified nodes on this bus */
|
||||||
int selfid_count; /* total number of SelfIDs received */
|
int selfid_count; /* total number of SelfIDs received */
|
||||||
int nodes_active; /* number of nodes that are actually active */
|
int nodes_active; /* number of nodes with active link layer */
|
||||||
|
u8 speed[63]; /* speed between each node and local node */
|
||||||
|
|
||||||
nodeid_t node_id; /* node ID of this host */
|
nodeid_t node_id; /* node ID of this host */
|
||||||
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
|
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
|
||||||
nodeid_t busmgr_id; /* ID of this bus' bus manager */
|
nodeid_t busmgr_id; /* ID of this bus' bus manager */
|
||||||
|
|
||||||
/* this nodes state */
|
/* this nodes state */
|
||||||
|
@ -285,9 +285,9 @@ static int check_selfids(struct hpsb_host *host)
|
|||||||
|
|
||||||
static void build_speed_map(struct hpsb_host *host, int nodecount)
|
static void build_speed_map(struct hpsb_host *host, int nodecount)
|
||||||
{
|
{
|
||||||
u8 speedcap[nodecount];
|
|
||||||
u8 cldcnt[nodecount];
|
u8 cldcnt[nodecount];
|
||||||
u8 *map = host->speed_map;
|
u8 *map = host->speed_map;
|
||||||
|
u8 *speedcap = host->speed;
|
||||||
struct selfid *sid;
|
struct selfid *sid;
|
||||||
struct ext_selfid *esid;
|
struct ext_selfid *esid;
|
||||||
int i, j, n;
|
int i, j, n;
|
||||||
@ -354,6 +354,11 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* assume maximum speed for 1394b PHYs, nodemgr will correct it */
|
||||||
|
for (n = 0; n < nodecount; n++)
|
||||||
|
if (speedcap[n] == 3)
|
||||||
|
speedcap[n] = IEEE1394_SPEED_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -554,11 +559,10 @@ int hpsb_send_packet(struct hpsb_packet *packet)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
|
if (packet->type == hpsb_async &&
|
||||||
|
NODEID_TO_NODE(packet->node_id) != ALL_NODES)
|
||||||
packet->speed_code =
|
packet->speed_code =
|
||||||
host->speed_map[NODEID_TO_NODE(host->node_id) * 64
|
host->speed[NODEID_TO_NODE(packet->node_id)];
|
||||||
+ NODEID_TO_NODE(packet->node_id)];
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
|
dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ struct nodemgr_csr_info {
|
|||||||
struct hpsb_host *host;
|
struct hpsb_host *host;
|
||||||
nodeid_t nodeid;
|
nodeid_t nodeid;
|
||||||
unsigned int generation;
|
unsigned int generation;
|
||||||
|
unsigned int speed_unverified:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -57,23 +58,75 @@ static char *nodemgr_find_oui_name(int oui)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Correct the speed map entry. This is necessary
|
||||||
|
* - for nodes with link speed < phy speed,
|
||||||
|
* - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
|
||||||
|
* A possible speed is determined by trial and error, using quadlet reads.
|
||||||
|
*/
|
||||||
|
static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
|
||||||
|
quadlet_t *buffer)
|
||||||
|
{
|
||||||
|
quadlet_t q;
|
||||||
|
u8 i, *speed, old_speed, good_speed;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid);
|
||||||
|
old_speed = *speed;
|
||||||
|
good_speed = IEEE1394_SPEED_MAX + 1;
|
||||||
|
|
||||||
|
/* Try every speed from S100 to old_speed.
|
||||||
|
* If we did it the other way around, a too low speed could be caught
|
||||||
|
* if the retry succeeded for some other reason, e.g. because the link
|
||||||
|
* just finished its initialization. */
|
||||||
|
for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
|
||||||
|
*speed = i;
|
||||||
|
ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
||||||
|
&q, sizeof(quadlet_t));
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
*buffer = q;
|
||||||
|
good_speed = i;
|
||||||
|
}
|
||||||
|
if (good_speed <= IEEE1394_SPEED_MAX) {
|
||||||
|
HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
|
||||||
|
NODE_BUS_ARGS(ci->host, ci->nodeid),
|
||||||
|
hpsb_speedto_str[good_speed]);
|
||||||
|
*speed = good_speed;
|
||||||
|
ci->speed_unverified = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*speed = old_speed;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
|
static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
|
||||||
void *buffer, void *__ci)
|
void *buffer, void *__ci)
|
||||||
{
|
{
|
||||||
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
|
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
|
||||||
int i, ret = 0;
|
int i, ret;
|
||||||
|
|
||||||
for (i = 1; ; i++) {
|
for (i = 1; ; i++) {
|
||||||
ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
||||||
buffer, length);
|
buffer, length);
|
||||||
if (!ret || i == 3)
|
if (!ret) {
|
||||||
|
ci->speed_unverified = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Give up after 3rd failure. */
|
||||||
|
if (i == 3)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* The ieee1394_core guessed the node's speed capability from
|
||||||
|
* the self ID. Check whether a lower speed works. */
|
||||||
|
if (ci->speed_unverified && length == sizeof(quadlet_t)) {
|
||||||
|
ret = nodemgr_check_speed(ci, addr, buffer);
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (msleep_interruptible(334))
|
if (msleep_interruptible(334))
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,6 +1257,8 @@ static void nodemgr_node_scan_one(struct host_info *hi,
|
|||||||
ci->host = host;
|
ci->host = host;
|
||||||
ci->nodeid = nodeid;
|
ci->nodeid = nodeid;
|
||||||
ci->generation = generation;
|
ci->generation = generation;
|
||||||
|
ci->speed_unverified =
|
||||||
|
host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100;
|
||||||
|
|
||||||
/* We need to detect when the ConfigROM's generation has changed,
|
/* We need to detect when the ConfigROM's generation has changed,
|
||||||
* so we only update the node's info when it needs to be. */
|
* so we only update the node's info when it needs to be. */
|
||||||
|
@ -1664,10 +1664,8 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
|
|||||||
|
|
||||||
SBP2_DEBUG_ENTER();
|
SBP2_DEBUG_ENTER();
|
||||||
|
|
||||||
/* Initial setting comes from the hosts speed map */
|
|
||||||
scsi_id->speed_code =
|
scsi_id->speed_code =
|
||||||
hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64 +
|
hi->host->speed[NODEID_TO_NODE(scsi_id->ne->nodeid)];
|
||||||
NODEID_TO_NODE(scsi_id->ne->nodeid)];
|
|
||||||
|
|
||||||
/* Bump down our speed if the user requested it */
|
/* Bump down our speed if the user requested it */
|
||||||
if (scsi_id->speed_code > max_speed) {
|
if (scsi_id->speed_code > max_speed) {
|
||||||
|
Loading…
Reference in New Issue
Block a user