mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-10-17 06:50:37 +08:00
Update to FreeBSD head 2016-12-10
Git mirror commit 80c55f08a05ab3b26a73b226ccb56adc3122a55c.
This commit is contained in:
@@ -3981,7 +3981,7 @@ pci_rescan_method(device_t dev)
|
||||
if (hdrtype & PCIM_MFDEV)
|
||||
pcifunchigh = PCIB_MAXFUNCS(pcib);
|
||||
for (f = 0; f <= pcifunchigh; f++) {
|
||||
if (REG(PCIR_VENDOR, 2) == 0xfff)
|
||||
if (REG(PCIR_VENDOR, 2) == 0xffff)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -4081,6 +4081,7 @@ pci_add_child(device_t bus, struct pci_devinfo *dinfo)
|
||||
pci_print_verbose(dinfo);
|
||||
pci_add_resources(bus, dinfo->cfg.dev, 0, 0);
|
||||
pci_child_added(dinfo->cfg.dev);
|
||||
EVENTHANDLER_INVOKE(pci_add_device, dinfo->cfg.dev);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4617,6 +4618,9 @@ static const struct
|
||||
{PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, 1, "entertainment crypto"},
|
||||
{PCIC_DASP, -1, 0, "dasp"},
|
||||
{PCIC_DASP, PCIS_DASP_DPIO, 1, "DPIO module"},
|
||||
{PCIC_DASP, PCIS_DASP_PERFCNTRS, 1, "performance counters"},
|
||||
{PCIC_DASP, PCIS_DASP_COMM_SYNC, 1, "communication synchronizer"},
|
||||
{PCIC_DASP, PCIS_DASP_MGMT_CARD, 1, "signal processing management"},
|
||||
{0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
@@ -5009,6 +5013,7 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
|
||||
struct resource_list *rl = &dinfo->resources;
|
||||
struct resource *res;
|
||||
struct pci_map *pm;
|
||||
uint16_t cmd;
|
||||
pci_addr_t map, testval;
|
||||
int mapsize;
|
||||
|
||||
@@ -5107,8 +5112,17 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
|
||||
device_printf(child,
|
||||
"Lazy allocation of %#jx bytes rid %#x type %d at %#jx\n",
|
||||
count, *rid, type, rman_get_start(res));
|
||||
|
||||
/* Disable decoding via the CMD register before updating the BAR */
|
||||
cmd = pci_read_config(child, PCIR_COMMAND, 2);
|
||||
pci_write_config(child, PCIR_COMMAND,
|
||||
cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2);
|
||||
|
||||
map = rman_get_start(res);
|
||||
pci_write_bar(child, pm, map);
|
||||
|
||||
/* Restore the original value of the CMD register */
|
||||
pci_write_config(child, PCIR_COMMAND, cmd, 2);
|
||||
out:
|
||||
return (res);
|
||||
}
|
||||
@@ -5331,6 +5345,8 @@ pci_child_deleted(device_t dev, device_t child)
|
||||
dinfo = device_get_ivars(child);
|
||||
rl = &dinfo->resources;
|
||||
|
||||
EVENTHANDLER_INVOKE(pci_delete_device, child);
|
||||
|
||||
/* Turn off access to resources we're about to free */
|
||||
if (bus_child_present(child) != 0) {
|
||||
pci_write_config(child, PCIR_COMMAND, pci_read_config(child,
|
||||
@@ -5908,3 +5924,165 @@ pci_find_pcie_root_port(device_t dev)
|
||||
dev = pcib;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for pending transactions to complete on a PCI-express function.
|
||||
*
|
||||
* The maximum delay is specified in milliseconds in max_delay. Note
|
||||
* that this function may sleep.
|
||||
*
|
||||
* Returns true if the function is idle and false if the timeout is
|
||||
* exceeded. If dev is not a PCI-express function, this returns true.
|
||||
*/
|
||||
bool
|
||||
pcie_wait_for_pending_transactions(device_t dev, u_int max_delay)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
uint16_t sta;
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0)
|
||||
return (true);
|
||||
|
||||
sta = pci_read_config(dev, cap + PCIER_DEVICE_STA, 2);
|
||||
while (sta & PCIEM_STA_TRANSACTION_PND) {
|
||||
if (max_delay == 0)
|
||||
return (false);
|
||||
|
||||
/* Poll once every 100 milliseconds up to the timeout. */
|
||||
if (max_delay > 100) {
|
||||
pause_sbt("pcietp", 100 * SBT_1MS, 0, C_HARDCLOCK);
|
||||
max_delay -= 100;
|
||||
} else {
|
||||
pause_sbt("pcietp", max_delay * SBT_1MS, 0,
|
||||
C_HARDCLOCK);
|
||||
max_delay = 0;
|
||||
}
|
||||
sta = pci_read_config(dev, cap + PCIER_DEVICE_STA, 2);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the maximum Completion Timeout in microseconds.
|
||||
*
|
||||
* For non-PCI-express functions this returns 0.
|
||||
*/
|
||||
int
|
||||
pcie_get_max_completion_timeout(device_t dev)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Functions using the 1.x spec use the default timeout range of
|
||||
* 50 microseconds to 50 milliseconds. Functions that do not
|
||||
* support programmable timeouts also use this range.
|
||||
*/
|
||||
if ((dinfo->cfg.pcie.pcie_flags & PCIEM_FLAGS_VERSION) < 2 ||
|
||||
(pci_read_config(dev, cap + PCIER_DEVICE_CAP2, 4) &
|
||||
PCIEM_CAP2_COMP_TIMO_RANGES) == 0)
|
||||
return (50 * 1000);
|
||||
|
||||
switch (pci_read_config(dev, cap + PCIER_DEVICE_CTL2, 2) &
|
||||
PCIEM_CTL2_COMP_TIMO_VAL) {
|
||||
case PCIEM_CTL2_COMP_TIMO_100US:
|
||||
return (100);
|
||||
case PCIEM_CTL2_COMP_TIMO_10MS:
|
||||
return (10 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_55MS:
|
||||
return (55 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_210MS:
|
||||
return (210 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_900MS:
|
||||
return (900 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_3500MS:
|
||||
return (3500 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_13S:
|
||||
return (13 * 1000 * 1000);
|
||||
case PCIEM_CTL2_COMP_TIMO_64S:
|
||||
return (64 * 1000 * 1000);
|
||||
default:
|
||||
return (50 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a Function Level Reset (FLR) on a device.
|
||||
*
|
||||
* This function first waits for any pending transactions to complete
|
||||
* within the timeout specified by max_delay. If transactions are
|
||||
* still pending, the function will return false without attempting a
|
||||
* reset.
|
||||
*
|
||||
* If dev is not a PCI-express function or does not support FLR, this
|
||||
* function returns false.
|
||||
*
|
||||
* Note that no registers are saved or restored. The caller is
|
||||
* responsible for saving and restoring any registers including
|
||||
* PCI-standard registers via pci_save_state() and
|
||||
* pci_restore_state().
|
||||
*/
|
||||
bool
|
||||
pcie_flr(device_t dev, u_int max_delay, bool force)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
uint16_t cmd, ctl;
|
||||
int compl_delay;
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0)
|
||||
return (false);
|
||||
|
||||
if (!(pci_read_config(dev, cap + PCIER_DEVICE_CAP, 4) & PCIEM_CAP_FLR))
|
||||
return (false);
|
||||
|
||||
/*
|
||||
* Disable busmastering to prevent generation of new
|
||||
* transactions while waiting for the device to go idle. If
|
||||
* the idle timeout fails, the command register is restored
|
||||
* which will re-enable busmastering.
|
||||
*/
|
||||
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
pci_write_config(dev, PCIR_COMMAND, cmd & ~(PCIM_CMD_BUSMASTEREN), 2);
|
||||
if (!pcie_wait_for_pending_transactions(dev, max_delay)) {
|
||||
if (!force) {
|
||||
pci_write_config(dev, PCIR_COMMAND, cmd, 2);
|
||||
return (false);
|
||||
}
|
||||
pci_printf(&dinfo->cfg,
|
||||
"Resetting with transactions pending after %d ms\n",
|
||||
max_delay);
|
||||
|
||||
/*
|
||||
* Extend the post-FLR delay to cover the maximum
|
||||
* Completion Timeout delay of anything in flight
|
||||
* during the FLR delay. Enforce a minimum delay of
|
||||
* at least 10ms.
|
||||
*/
|
||||
compl_delay = pcie_get_max_completion_timeout(dev) / 1000;
|
||||
if (compl_delay < 10)
|
||||
compl_delay = 10;
|
||||
} else
|
||||
compl_delay = 0;
|
||||
|
||||
/* Initiate the reset. */
|
||||
ctl = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
|
||||
pci_write_config(dev, cap + PCIER_DEVICE_CTL, ctl |
|
||||
PCIEM_CTL_INITIATE_FLR, 2);
|
||||
|
||||
/* Wait for 100ms. */
|
||||
pause_sbt("pcieflr", (100 + compl_delay) * SBT_1MS, 0, C_HARDCLOCK);
|
||||
|
||||
if (pci_read_config(dev, cap + PCIER_DEVICE_STA, 2) &
|
||||
PCIEM_STA_TRANSACTION_PND)
|
||||
pci_printf(&dinfo->cfg, "Transactions pending after FLR!\n");
|
||||
return (true);
|
||||
}
|
||||
|
Reference in New Issue
Block a user