Changeset View
Standalone View
sys/powerpc/powernv/opal_pci.c
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include "pcib_if.h" | #include "pcib_if.h" | ||||
#include "pic_if.h" | #include "pic_if.h" | ||||
#include "iommu_if.h" | #include "iommu_if.h" | ||||
#include "opal.h" | #include "opal.h" | ||||
#define OPAL_PCI_TCE_MAX_ENTRIES (1024*1024UL) | #define OPAL_PCI_TCE_MAX_ENTRIES (1024*1024UL) | ||||
#define OPAL_PCI_TCE_SEG_SIZE (16*1024*1024UL) | #define OPAL_PCI_TCE_DEFAULT_SEG_SIZE (16*1024*1024UL) | ||||
#define OPAL_PCI_TCE_R (1UL << 0) | #define OPAL_PCI_TCE_R (1UL << 0) | ||||
#define OPAL_PCI_TCE_W (1UL << 1) | #define OPAL_PCI_TCE_W (1UL << 1) | ||||
#define PHB3_TCE_KILL_INVAL_ALL (1UL << 63) | #define PHB3_TCE_KILL_INVAL_ALL (1UL << 63) | ||||
/* | /* | ||||
* Device interface. | * Device interface. | ||||
*/ | */ | ||||
static int opalpci_probe(device_t); | static int opalpci_probe(device_t); | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
pci_phb3_tce_invalidate_entire(struct opalpci_softc *sc) | pci_phb3_tce_invalidate_entire(struct opalpci_softc *sc) | ||||
{ | { | ||||
mb(); | mb(); | ||||
bus_write_8(sc->r_reg, 0x210, PHB3_TCE_KILL_INVAL_ALL); | bus_write_8(sc->r_reg, 0x210, PHB3_TCE_KILL_INVAL_ALL); | ||||
mb(); | mb(); | ||||
} | } | ||||
/* Simple function to round to a power of 2 */ | |||||
static uint64_t | |||||
round_pow2(uint64_t val) | |||||
imp: sys/param.h defines roundup2 and rounddown2 for this purpose. | |||||
Not Done Inline ActionsNot quite. roundup2/rounddown2 take a power of 2 as 'y', and rounds 'x' to a multiple of 'y'. In this case, I'm trying to round up to the nearest power of 2. jhibbits: Not quite. roundup2/rounddown2 take a power of 2 as 'y', and rounds 'x' to a multiple of 'y'. | |||||
{ | |||||
return (1 << (flsl(val + (val - 1)) - 1)); | |||||
} | |||||
/* | |||||
* Starting with skiboot 5.10 PCIe nodes have a new property, | |||||
* "ibm,supported-tce-sizes", to denote the TCE sizes available. This allows us | |||||
* to avoid hard-coding the maximum TCE size allowed, and instead provide a sane | |||||
* default (however, the "sane" default, which works for all targets, is 64k, | |||||
* limiting us to 64GB if we have 1M entries. | |||||
*/ | |||||
static uint64_t | |||||
max_tce_size(device_t dev) | |||||
{ | |||||
phandle_t node; | |||||
cell_t sizes[64]; /* Property is a list of bit-widths, up to 64-bits */ | |||||
int count; | |||||
node = ofw_bus_get_node(dev); | |||||
count = OF_getencprop(node, "ibm,supported-tce-sizes", | |||||
sizes, sizeof(sizes)); | |||||
if (count < sizeof(cell_t)) | |||||
return OPAL_PCI_TCE_DEFAULT_SEG_SIZE; | |||||
count /= sizeof(cell_t); | |||||
return (1ULL << sizes[count - 1]); | |||||
} | |||||
static int | static int | ||||
opalpci_attach(device_t dev) | opalpci_attach(device_t dev) | ||||
{ | { | ||||
struct opalpci_softc *sc; | struct opalpci_softc *sc; | ||||
cell_t id[2], m64window[6], npe; | cell_t id[2], m64ranges[2], m64window[6], npe; | ||||
phandle_t node; | |||||
int i, err; | int i, err; | ||||
uint64_t maxmem; | uint64_t maxmem; | ||||
uint64_t entries; | uint64_t entries; | ||||
uint64_t tce_size; | |||||
uint64_t tce_tbl_size; | |||||
int m64bar; | |||||
int rid; | int rid; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
node = ofw_bus_get_node(dev); | |||||
switch (OF_getproplen(ofw_bus_get_node(dev), "ibm,opal-phbid")) { | switch (OF_getproplen(node, "ibm,opal-phbid")) { | ||||
case 8: | case 8: | ||||
OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-phbid", id, 8); | OF_getencprop(node, "ibm,opal-phbid", id, 8); | ||||
sc->phb_id = ((uint64_t)id[0] << 32) | id[1]; | sc->phb_id = ((uint64_t)id[0] << 32) | id[1]; | ||||
break; | break; | ||||
case 4: | case 4: | ||||
OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-phbid", id, 4); | OF_getencprop(node, "ibm,opal-phbid", id, 4); | ||||
sc->phb_id = id[0]; | sc->phb_id = id[0]; | ||||
break; | break; | ||||
default: | default: | ||||
device_printf(dev, "PHB ID property had wrong length (%zd)\n", | device_printf(dev, "PHB ID property had wrong length (%zd)\n", | ||||
OF_getproplen(ofw_bus_get_node(dev), "ibm,opal-phbid")); | OF_getproplen(node, "ibm,opal-phbid")); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "OPAL ID %#lx\n", sc->phb_id); | device_printf(dev, "OPAL ID %#lx\n", sc->phb_id); | ||||
rid = 0; | rid = 0; | ||||
sc->r_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | sc->r_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&rid, RF_ACTIVE | RF_SHAREABLE); | &rid, RF_ACTIVE | RF_SHAREABLE); | ||||
if (sc->r_reg == NULL) { | if (sc->r_reg == NULL) { | ||||
device_printf(dev, "Failed to allocate PHB[%jd] registers\n", | device_printf(dev, "Failed to allocate PHB[%jd] registers\n", | ||||
(uintmax_t)sc->phb_id); | (uintmax_t)sc->phb_id); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
#if 0 | |||||
Not Done Inline ActionsIs this intentional? imp: Is this intentional? | |||||
Not Done Inline ActionsKind of. It's work in progress. I don't want to throw it away, because this is part of the "proper" initialization, which Linux does. It's blocked out for now, because it doesn't fully work, and I haven't yet found the missing pieces for it. jhibbits: Kind of. It's work in progress. I don't want to throw it away, because this is part of the… | |||||
Not Done Inline ActionsI think it didn't work on P8 either, at least with the newest OPAL. However, on P8 it only produces a warning during boot and does not influence anything further. wma: I think it didn't work on P8 either, at least with the newest OPAL. However, on P8 it only… | |||||
/* | /* | ||||
* Reset PCI IODA table | * Reset PCI IODA table | ||||
*/ | */ | ||||
err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PCI_IODA_TABLE, | err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PCI_IODA_TABLE, | ||||
1); | 1); | ||||
if (err != 0) { | if (err != 0) { | ||||
device_printf(dev, "IODA table reset failed: %d\n", err); | device_printf(dev, "IODA table reset failed: %d\n", err); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) | err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PHB_COMPLETE, | ||||
1); | |||||
if (err < 0) { | |||||
device_printf(dev, "PHB reset failed: %d\n", err); | |||||
return (ENXIO); | |||||
} | |||||
if (err > 0) { | |||||
while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) { | |||||
DELAY(1000*(err + 1)); /* Returns expected delay in ms */ | DELAY(1000*(err + 1)); /* Returns expected delay in ms */ | ||||
} | |||||
} | |||||
if (err < 0) { | if (err < 0) { | ||||
device_printf(dev, "WARNING: PHB IODA reset poll failed: %d\n", err); | device_printf(dev, "WARNING: PHB IODA reset poll failed: %d\n", err); | ||||
} | } | ||||
err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PHB_COMPLETE, | |||||
0); | |||||
if (err < 0) { | |||||
device_printf(dev, "PHB reset failed: %d\n", err); | |||||
return (ENXIO); | |||||
} | |||||
if (err > 0) { | |||||
while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) { | |||||
DELAY(1000*(err + 1)); /* Returns expected delay in ms */ | |||||
} | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Map all devices on the bus to partitionable endpoint one until | * Map all devices on the bus to partitionable endpoint one until | ||||
* such time as we start wanting to do things like bhyve. | * such time as we start wanting to do things like bhyve. | ||||
*/ | */ | ||||
err = opal_call(OPAL_PCI_SET_PE, sc->phb_id, OPAL_PCI_DEFAULT_PE, | err = opal_call(OPAL_PCI_SET_PE, sc->phb_id, OPAL_PCI_DEFAULT_PE, | ||||
0, OPAL_PCI_BUS_ANY, OPAL_IGNORE_RID_DEVICE_NUMBER, | 0, OPAL_PCI_BUS_ANY, OPAL_IGNORE_RID_DEVICE_NUMBER, | ||||
OPAL_IGNORE_RID_FUNC_NUMBER, OPAL_MAP_PE); | OPAL_IGNORE_RID_FUNC_NUMBER, OPAL_MAP_PE); | ||||
if (err != 0) { | if (err != 0) { | ||||
device_printf(dev, "PE mapping failed: %d\n", err); | device_printf(dev, "PE mapping failed: %d\n", err); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* | /* | ||||
* Turn on MMIO, mapped to PE 1 | * Turn on MMIO, mapped to PE 1 | ||||
*/ | */ | ||||
if (OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-num-pes", &npe, 4) | if (OF_getencprop(node, "ibm,opal-num-pes", &npe, 4) != 4) | ||||
!= 4) | |||||
npe = 1; | npe = 1; | ||||
for (i = 0; i < npe; i++) { | for (i = 0; i < npe; i++) { | ||||
err = opal_call(OPAL_PCI_MAP_PE_MMIO_WINDOW, sc->phb_id, | err = opal_call(OPAL_PCI_MAP_PE_MMIO_WINDOW, sc->phb_id, | ||||
OPAL_PCI_DEFAULT_PE, OPAL_M32_WINDOW_TYPE, 0, i); | OPAL_PCI_DEFAULT_PE, OPAL_M32_WINDOW_TYPE, 0, i); | ||||
if (err != 0) | if (err != 0) | ||||
device_printf(dev, "MMIO %d map failed: %d\n", i, err); | device_printf(dev, "MMIO %d map failed: %d\n", i, err); | ||||
} | } | ||||
if (OF_getencprop(node, "ibm,opal-available-m64-ranges", | |||||
m64ranges, sizeof(m64ranges)) == sizeof(m64ranges)) | |||||
m64bar = m64ranges[0]; | |||||
else | |||||
m64bar = 0; | |||||
/* XXX: multiple M64 windows? */ | /* XXX: multiple M64 windows? */ | ||||
if (OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-m64-window", | if (OF_getencprop(node, "ibm,opal-m64-window", | ||||
m64window, sizeof(m64window)) == sizeof(m64window)) { | m64window, sizeof(m64window)) == sizeof(m64window)) { | ||||
opal_call(OPAL_PCI_PHB_MMIO_ENABLE, sc->phb_id, | opal_call(OPAL_PCI_PHB_MMIO_ENABLE, sc->phb_id, | ||||
OPAL_M64_WINDOW_TYPE, 0, 0); | OPAL_M64_WINDOW_TYPE, m64bar, 0); | ||||
opal_call(OPAL_PCI_SET_PHB_MEM_WINDOW, sc->phb_id, | opal_call(OPAL_PCI_SET_PHB_MEM_WINDOW, sc->phb_id, | ||||
OPAL_M64_WINDOW_TYPE, 0 /* index */, | OPAL_M64_WINDOW_TYPE, m64bar /* index */, | ||||
((uint64_t)m64window[2] << 32) | m64window[3], 0, | ((uint64_t)m64window[2] << 32) | m64window[3], 0, | ||||
((uint64_t)m64window[4] << 32) | m64window[5]); | ((uint64_t)m64window[4] << 32) | m64window[5]); | ||||
opal_call(OPAL_PCI_MAP_PE_MMIO_WINDOW, sc->phb_id, | opal_call(OPAL_PCI_MAP_PE_MMIO_WINDOW, sc->phb_id, | ||||
Not Done Inline ActionsLikewise. imp: Likewise. | |||||
Not Done Inline ActionsThis might be a casualty of my testing. I'll have to retest it to be sure. jhibbits: This might be a casualty of my testing. I'll have to retest it to be sure. | |||||
OPAL_PCI_DEFAULT_PE, OPAL_M64_WINDOW_TYPE, | OPAL_PCI_DEFAULT_PE, OPAL_M64_WINDOW_TYPE, | ||||
0 /* index */, 0); | m64bar /* index */, 0); | ||||
opal_call(OPAL_PCI_PHB_MMIO_ENABLE, sc->phb_id, | opal_call(OPAL_PCI_PHB_MMIO_ENABLE, sc->phb_id, | ||||
OPAL_M64_WINDOW_TYPE, 0, OPAL_ENABLE_M64_NON_SPLIT); | OPAL_M64_WINDOW_TYPE, m64bar, OPAL_ENABLE_M64_NON_SPLIT); | ||||
Done Inline ActionsThis might be worth testing on P8 also. If I recall correctly, there were sth messed up with using splitted windows... wma: This might be worth testing on P8 also. If I recall correctly, there were sth messed up with… | |||||
Not Done Inline ActionsYeah, it didn't work on POWER9 either, and I was pretty sure I had reverted it before submitting for review. I tested both cases, including post-revert. With split windows bge couldn't find its phy, after reverting to non-split windows, bge could initialize correctly. jhibbits: Yeah, it didn't work on POWER9 either, and I was pretty sure I had reverted it before… | |||||
} | } | ||||
/* | /* | ||||
* Enable IOMMU for PE1 - map everything 1:1 using | * Enable IOMMU for PE1 - map everything 1:1 using | ||||
* segments of OPAL_PCI_TCE_SEG_SIZE size | * segments of max_tce_size size | ||||
*/ | */ | ||||
maxmem = roundup2(powerpc_ptob(Maxmem), OPAL_PCI_TCE_SEG_SIZE); | tce_size = max_tce_size(dev); | ||||
entries = maxmem / OPAL_PCI_TCE_SEG_SIZE; | maxmem = roundup2(powerpc_ptob(Maxmem), tce_size); | ||||
entries = round_pow2(maxmem / tce_size); | |||||
tce_tbl_size = max(entries * sizeof(uint64_t), 4096); | |||||
device_printf(dev, "Entries: %ld, tce_size: %#lx\n", entries, tce_size); | |||||
if (entries > OPAL_PCI_TCE_MAX_ENTRIES) | if (entries > OPAL_PCI_TCE_MAX_ENTRIES) | ||||
panic("POWERNV supports only %jdGB of memory space\n", | panic("POWERNV supports only %jdGB of memory space\n", | ||||
(uintmax_t)((OPAL_PCI_TCE_MAX_ENTRIES * OPAL_PCI_TCE_SEG_SIZE) >> 30)); | (uintmax_t)((OPAL_PCI_TCE_MAX_ENTRIES * tce_size) >> 30)); | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "Mapping 0-%#jx for DMA\n", (uintmax_t)maxmem); | device_printf(dev, "Mapping 0-%#jx for DMA\n", (uintmax_t)maxmem); | ||||
sc->tce = contigmalloc(OPAL_PCI_TCE_MAX_ENTRIES * sizeof(uint64_t), | sc->tce = contigmalloc(tce_tbl_size, | ||||
M_DEVBUF, M_NOWAIT | M_ZERO, 0, | M_DEVBUF, M_NOWAIT | M_ZERO, 0, | ||||
BUS_SPACE_MAXADDR_32BIT, OPAL_PCI_TCE_SEG_SIZE, 0); | BUS_SPACE_MAXADDR, tce_size, 0); | ||||
if (sc->tce == NULL) | if (sc->tce == NULL) | ||||
panic("Failed to allocate TCE memory for PHB %jd\n", | panic("Failed to allocate TCE memory for PHB %jd\n", | ||||
(uintmax_t)sc->phb_id); | (uintmax_t)sc->phb_id); | ||||
for (i = 0; i < entries; i++) | for (i = 0; i < entries; i++) | ||||
sc->tce[i] = (i * OPAL_PCI_TCE_SEG_SIZE) | OPAL_PCI_TCE_R | OPAL_PCI_TCE_W; | sc->tce[i] = (i * tce_size) | OPAL_PCI_TCE_R | OPAL_PCI_TCE_W; | ||||
/* Map TCE for every PE. It seems necessary for Power8 */ | /* Map TCE for every PE. It seems necessary for Power8 */ | ||||
for (i = 0; i < npe; i++) { | for (i = 0; i < npe; i++) { | ||||
err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW, sc->phb_id, | err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW, sc->phb_id, | ||||
i, (i << 1), | i, (i << 1), | ||||
1, pmap_kextract((uint64_t)&sc->tce[0]), | 1, pmap_kextract((uint64_t)&sc->tce[0]), | ||||
OPAL_PCI_TCE_MAX_ENTRIES * sizeof(uint64_t), OPAL_PCI_TCE_SEG_SIZE); | tce_tbl_size, tce_size); | ||||
if (err != 0) { | if (err != 0) { | ||||
device_printf(dev, "DMA IOMMU mapping failed: %d\n", err); | device_printf(dev, "DMA IOMMU mapping failed: %d\n", err); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, sc->phb_id, | err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, sc->phb_id, | ||||
i, (i << 1) + 1, | i, (i << 1) + 1, | ||||
(1UL << 59), maxmem); | (1UL << 59), maxmem); | ||||
Show All 9 Lines | #endif | ||||
* TODO: add support for other PHBs than PHB3 | * TODO: add support for other PHBs than PHB3 | ||||
*/ | */ | ||||
pci_phb3_tce_invalidate_entire(sc); | pci_phb3_tce_invalidate_entire(sc); | ||||
/* | /* | ||||
* Get MSI properties | * Get MSI properties | ||||
*/ | */ | ||||
sc->msi_vmem = NULL; | sc->msi_vmem = NULL; | ||||
if (OF_getproplen(ofw_bus_get_node(dev), "ibm,opal-msi-ranges") > 0) { | if (OF_getproplen(node, "ibm,opal-msi-ranges") > 0) { | ||||
breno.leitao_gmail.comUnsubmitted Not Done Inline ActionsCan't you just call OF_getencprop() and checking if the return > 0, if so proceeding to branch other than calling OF_getproplen() and OF_getencprop()? breno.leitao_gmail.com: Can't you just call OF_getencprop() and checking if the return > 0, if so proceeding to branch… | |||||
jhibbitsAuthorUnsubmitted Not Done Inline ActionsYeah, that would be saner. This change, and most of the OF_* changes, are just a rename of ofw_bus_get_node(dev) -> node. I'll commit that change separately though, since it't a non-functional change. I plan to make further changes to this file after I get the initial working skeleton in, for performance and stability. jhibbits: Yeah, that would be saner.
This change, and most of the OF_* changes, are just a rename of… | |||||
cell_t msi_ranges[2]; | cell_t msi_ranges[2]; | ||||
OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-msi-ranges", | OF_getencprop(node, "ibm,opal-msi-ranges", | ||||
msi_ranges, sizeof(msi_ranges)); | msi_ranges, sizeof(msi_ranges)); | ||||
sc->msi_base = msi_ranges[0]; | sc->msi_base = msi_ranges[0]; | ||||
sc->msi_vmem = vmem_create("OPAL MSI", msi_ranges[0], | sc->msi_vmem = vmem_create("OPAL MSI", msi_ranges[0], | ||||
msi_ranges[1], 1, 16, M_BESTFIT | M_WAITOK); | msi_ranges[1], 1, 16, M_BESTFIT | M_WAITOK); | ||||
sc->base_msi_irq = powerpc_register_pic(dev, | sc->base_msi_irq = powerpc_register_pic(dev, | ||||
OF_xref_from_node(ofw_bus_get_node(dev)), | OF_xref_from_node(node), | ||||
msi_ranges[0] + msi_ranges[1], 0, FALSE); | msi_ranges[0] + msi_ranges[1], 0, FALSE); | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "Supports %d MSIs starting at %d\n", | device_printf(dev, "Supports %d MSIs starting at %d\n", | ||||
msi_ranges[1], msi_ranges[0]); | msi_ranges[1], msi_ranges[0]); | ||||
} | } | ||||
/* | /* | ||||
* General OFW PCI attach | * General OFW PCI attach | ||||
*/ | */ | ||||
err = ofw_pci_init(dev); | err = ofw_pci_init(dev); | ||||
if (err != 0) | if (err != 0) | ||||
return (err); | return (err); | ||||
/* | /* | ||||
* Unfreeze non-config-space PCI operations. Let this fail silently | * Unfreeze non-config-space PCI operations. Let this fail silently | ||||
* if e.g. there is no current freeze. | * if e.g. there is no current freeze. | ||||
*/ | */ | ||||
opal_call(OPAL_PCI_EEH_FREEZE_CLEAR, sc->phb_id, OPAL_PCI_DEFAULT_PE, | opal_call(OPAL_PCI_EEH_FREEZE_CLEAR, sc->phb_id, OPAL_PCI_DEFAULT_PE, | ||||
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); | OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); | ||||
/* | /* | ||||
* OPAL stores 64-bit BARs in a special property rather than "ranges" | * OPAL stores 64-bit BARs in a special property rather than "ranges" | ||||
*/ | */ | ||||
if (OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-m64-window", | if (OF_getencprop(node, "ibm,opal-m64-window", | ||||
m64window, sizeof(m64window)) == sizeof(m64window)) { | m64window, sizeof(m64window)) == sizeof(m64window)) { | ||||
struct ofw_pci_range *rp; | struct ofw_pci_range *rp; | ||||
sc->ofw_sc.sc_nrange++; | sc->ofw_sc.sc_nrange++; | ||||
sc->ofw_sc.sc_range = realloc(sc->ofw_sc.sc_range, | sc->ofw_sc.sc_range = realloc(sc->ofw_sc.sc_range, | ||||
sc->ofw_sc.sc_nrange * sizeof(sc->ofw_sc.sc_range[0]), | sc->ofw_sc.sc_nrange * sizeof(sc->ofw_sc.sc_range[0]), | ||||
M_DEVBUF, M_WAITOK); | M_DEVBUF, M_WAITOK); | ||||
rp = &sc->ofw_sc.sc_range[sc->ofw_sc.sc_nrange-1]; | rp = &sc->ofw_sc.sc_range[sc->ofw_sc.sc_nrange-1]; | ||||
▲ Show 20 Lines • Show All 226 Lines • Show Last 20 Lines |
sys/param.h defines roundup2 and rounddown2 for this purpose.