net/ncsi: Probe single packages to avoid conflict
Currently the NCSI driver sends a select-package command to all possible packages simultaneously to discover what packages are available. However at this stage in the probe process the driver does not know if hardware arbitration is available: if it isn't then this process could cause collisions on the RMII bus when packages try to respond. Update the probe loop to probe each package one by one, and once complete check if HWA is universally supported. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
60ab49bfe4
commit
8e13f70be0
|
@ -292,6 +292,7 @@ struct ncsi_dev_priv {
|
|||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unsigned int inet6_addr_num; /* Number of IPv6 addresses */
|
||||
#endif
|
||||
unsigned int package_probe_id;/* Current ID during probe */
|
||||
unsigned int package_num; /* Number of packages */
|
||||
struct list_head packages; /* List of packages */
|
||||
struct ncsi_channel *hot_channel; /* Channel was ever active */
|
||||
|
|
|
@ -1079,67 +1079,28 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||
nd->state = ncsi_dev_state_probe_package;
|
||||
break;
|
||||
case ncsi_dev_state_probe_package:
|
||||
ndp->pending_req_num = 16;
|
||||
|
||||
/* Select all possible packages */
|
||||
nca.type = NCSI_PKT_CMD_SP;
|
||||
nca.bytes[0] = 1;
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
for (index = 0; index < 8; index++) {
|
||||
nca.package = index;
|
||||
ret = ncsi_xmit_cmd(&nca);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Disable all possible packages */
|
||||
nca.type = NCSI_PKT_CMD_DP;
|
||||
for (index = 0; index < 8; index++) {
|
||||
nca.package = index;
|
||||
ret = ncsi_xmit_cmd(&nca);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
nd->state = ncsi_dev_state_probe_channel;
|
||||
break;
|
||||
case ncsi_dev_state_probe_channel:
|
||||
if (!ndp->active_package)
|
||||
ndp->active_package = list_first_or_null_rcu(
|
||||
&ndp->packages, struct ncsi_package, node);
|
||||
else if (list_is_last(&ndp->active_package->node,
|
||||
&ndp->packages))
|
||||
ndp->active_package = NULL;
|
||||
else
|
||||
ndp->active_package = list_next_entry(
|
||||
ndp->active_package, node);
|
||||
|
||||
/* All available packages and channels are enumerated. The
|
||||
* enumeration happens for once when the NCSI interface is
|
||||
* started. So we need continue to start the interface after
|
||||
* the enumeration.
|
||||
*
|
||||
* We have to choose an active channel before configuring it.
|
||||
* Note that we possibly don't have active channel in extreme
|
||||
* situation.
|
||||
*/
|
||||
if (!ndp->active_package) {
|
||||
ndp->flags |= NCSI_DEV_PROBED;
|
||||
ncsi_choose_active_channel(ndp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select the active package */
|
||||
ndp->pending_req_num = 1;
|
||||
|
||||
nca.type = NCSI_PKT_CMD_SP;
|
||||
nca.bytes[0] = 1;
|
||||
nca.package = ndp->active_package->id;
|
||||
nca.package = ndp->package_probe_id;
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
ret = ncsi_xmit_cmd(&nca);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
nd->state = ncsi_dev_state_probe_channel;
|
||||
break;
|
||||
case ncsi_dev_state_probe_channel:
|
||||
ndp->active_package = ncsi_find_package(ndp,
|
||||
ndp->package_probe_id);
|
||||
if (!ndp->active_package) {
|
||||
/* No response */
|
||||
nd->state = ncsi_dev_state_probe_dp;
|
||||
schedule_work(&ndp->work);
|
||||
break;
|
||||
}
|
||||
nd->state = ncsi_dev_state_probe_cis;
|
||||
schedule_work(&ndp->work);
|
||||
break;
|
||||
case ncsi_dev_state_probe_cis:
|
||||
ndp->pending_req_num = NCSI_RESERVED_CHANNEL;
|
||||
|
@ -1188,22 +1149,35 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||
case ncsi_dev_state_probe_dp:
|
||||
ndp->pending_req_num = 1;
|
||||
|
||||
/* Deselect the active package */
|
||||
/* Deselect the current package */
|
||||
nca.type = NCSI_PKT_CMD_DP;
|
||||
nca.package = ndp->active_package->id;
|
||||
nca.package = ndp->package_probe_id;
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
ret = ncsi_xmit_cmd(&nca);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Scan channels in next package */
|
||||
nd->state = ncsi_dev_state_probe_channel;
|
||||
/* Probe next package */
|
||||
ndp->package_probe_id++;
|
||||
if (ndp->package_probe_id >= 8) {
|
||||
/* Probe finished */
|
||||
ndp->flags |= NCSI_DEV_PROBED;
|
||||
break;
|
||||
}
|
||||
nd->state = ncsi_dev_state_probe_package;
|
||||
ndp->active_package = NULL;
|
||||
break;
|
||||
default:
|
||||
netdev_warn(nd->dev, "Wrong NCSI state 0x%0x in enumeration\n",
|
||||
nd->state);
|
||||
}
|
||||
|
||||
if (ndp->flags & NCSI_DEV_PROBED) {
|
||||
/* Check if all packages have HWA support */
|
||||
ncsi_check_hwa(ndp);
|
||||
ncsi_choose_active_channel(ndp);
|
||||
}
|
||||
|
||||
return;
|
||||
error:
|
||||
netdev_err(ndp->ndev.dev,
|
||||
|
@ -1564,6 +1538,7 @@ int ncsi_start_dev(struct ncsi_dev *nd)
|
|||
return -ENOTTY;
|
||||
|
||||
if (!(ndp->flags & NCSI_DEV_PROBED)) {
|
||||
ndp->package_probe_id = 0;
|
||||
nd->state = ncsi_dev_state_probe;
|
||||
schedule_work(&ndp->work);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue