diff options
| -rw-r--r-- | arch/powerpc/include/asm/pci-bridge.h | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 197 |
2 files changed, 154 insertions, 45 deletions
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 415df8509f52..560c73996474 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h | |||
| @@ -185,7 +185,7 @@ struct pci_dn { | |||
| 185 | #define M64_PER_IOV 4 | 185 | #define M64_PER_IOV 4 |
| 186 | int m64_per_iov; | 186 | int m64_per_iov; |
| 187 | #define IODA_INVALID_M64 (-1) | 187 | #define IODA_INVALID_M64 (-1) |
| 188 | int m64_wins[PCI_SRIOV_NUM_BARS]; | 188 | int m64_wins[PCI_SRIOV_NUM_BARS][M64_PER_IOV]; |
| 189 | #endif /* CONFIG_PCI_IOV */ | 189 | #endif /* CONFIG_PCI_IOV */ |
| 190 | #endif | 190 | #endif |
| 191 | struct list_head child_list; | 191 | struct list_head child_list; |
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index b63925f483fc..33088f6f7328 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
| @@ -1156,26 +1156,27 @@ static int pnv_pci_vf_release_m64(struct pci_dev *pdev) | |||
| 1156 | struct pci_controller *hose; | 1156 | struct pci_controller *hose; |
| 1157 | struct pnv_phb *phb; | 1157 | struct pnv_phb *phb; |
| 1158 | struct pci_dn *pdn; | 1158 | struct pci_dn *pdn; |
| 1159 | int i; | 1159 | int i, j; |
| 1160 | 1160 | ||
| 1161 | bus = pdev->bus; | 1161 | bus = pdev->bus; |
| 1162 | hose = pci_bus_to_host(bus); | 1162 | hose = pci_bus_to_host(bus); |
| 1163 | phb = hose->private_data; | 1163 | phb = hose->private_data; |
| 1164 | pdn = pci_get_pdn(pdev); | 1164 | pdn = pci_get_pdn(pdev); |
| 1165 | 1165 | ||
| 1166 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { | 1166 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) |
| 1167 | if (pdn->m64_wins[i] == IODA_INVALID_M64) | 1167 | for (j = 0; j < M64_PER_IOV; j++) { |
| 1168 | continue; | 1168 | if (pdn->m64_wins[i][j] == IODA_INVALID_M64) |
| 1169 | opal_pci_phb_mmio_enable(phb->opal_id, | 1169 | continue; |
| 1170 | OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 0); | 1170 | opal_pci_phb_mmio_enable(phb->opal_id, |
| 1171 | clear_bit(pdn->m64_wins[i], &phb->ioda.m64_bar_alloc); | 1171 | OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 0); |
| 1172 | pdn->m64_wins[i] = IODA_INVALID_M64; | 1172 | clear_bit(pdn->m64_wins[i][j], &phb->ioda.m64_bar_alloc); |
| 1173 | } | 1173 | pdn->m64_wins[i][j] = IODA_INVALID_M64; |
| 1174 | } | ||
| 1174 | 1175 | ||
| 1175 | return 0; | 1176 | return 0; |
| 1176 | } | 1177 | } |
| 1177 | 1178 | ||
| 1178 | static int pnv_pci_vf_assign_m64(struct pci_dev *pdev) | 1179 | static int pnv_pci_vf_assign_m64(struct pci_dev *pdev, u16 num_vfs) |
| 1179 | { | 1180 | { |
| 1180 | struct pci_bus *bus; | 1181 | struct pci_bus *bus; |
| 1181 | struct pci_controller *hose; | 1182 | struct pci_controller *hose; |
| @@ -1183,17 +1184,33 @@ static int pnv_pci_vf_assign_m64(struct pci_dev *pdev) | |||
| 1183 | struct pci_dn *pdn; | 1184 | struct pci_dn *pdn; |
| 1184 | unsigned int win; | 1185 | unsigned int win; |
| 1185 | struct resource *res; | 1186 | struct resource *res; |
| 1186 | int i; | 1187 | int i, j; |
| 1187 | int64_t rc; | 1188 | int64_t rc; |
| 1189 | int total_vfs; | ||
| 1190 | resource_size_t size, start; | ||
| 1191 | int pe_num; | ||
| 1192 | int vf_groups; | ||
| 1193 | int vf_per_group; | ||
| 1188 | 1194 | ||
| 1189 | bus = pdev->bus; | 1195 | bus = pdev->bus; |
| 1190 | hose = pci_bus_to_host(bus); | 1196 | hose = pci_bus_to_host(bus); |
| 1191 | phb = hose->private_data; | 1197 | phb = hose->private_data; |
| 1192 | pdn = pci_get_pdn(pdev); | 1198 | pdn = pci_get_pdn(pdev); |
| 1199 | total_vfs = pci_sriov_get_totalvfs(pdev); | ||
| 1193 | 1200 | ||
| 1194 | /* Initialize the m64_wins to IODA_INVALID_M64 */ | 1201 | /* Initialize the m64_wins to IODA_INVALID_M64 */ |
| 1195 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) | 1202 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) |
| 1196 | pdn->m64_wins[i] = IODA_INVALID_M64; | 1203 | for (j = 0; j < M64_PER_IOV; j++) |
| 1204 | pdn->m64_wins[i][j] = IODA_INVALID_M64; | ||
| 1205 | |||
| 1206 | if (pdn->m64_per_iov == M64_PER_IOV) { | ||
| 1207 | vf_groups = (num_vfs <= M64_PER_IOV) ? num_vfs: M64_PER_IOV; | ||
| 1208 | vf_per_group = (num_vfs <= M64_PER_IOV)? 1: | ||
| 1209 | roundup_pow_of_two(num_vfs) / pdn->m64_per_iov; | ||
| 1210 | } else { | ||
| 1211 | vf_groups = 1; | ||
| 1212 | vf_per_group = 1; | ||
| 1213 | } | ||
| 1197 | 1214 | ||
| 1198 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { | 1215 | for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { |
| 1199 | res = &pdev->resource[i + PCI_IOV_RESOURCES]; | 1216 | res = &pdev->resource[i + PCI_IOV_RESOURCES]; |
| @@ -1203,35 +1220,61 @@ static int pnv_pci_vf_assign_m64(struct pci_dev *pdev) | |||
| 1203 | if (!pnv_pci_is_mem_pref_64(res->flags)) | 1220 | if (!pnv_pci_is_mem_pref_64(res->flags)) |
| 1204 | continue; | 1221 | continue; |
| 1205 | 1222 | ||
| 1206 | do { | 1223 | for (j = 0; j < vf_groups; j++) { |
| 1207 | win = find_next_zero_bit(&phb->ioda.m64_bar_alloc, | 1224 | do { |
| 1208 | phb->ioda.m64_bar_idx + 1, 0); | 1225 | win = find_next_zero_bit(&phb->ioda.m64_bar_alloc, |
| 1209 | 1226 | phb->ioda.m64_bar_idx + 1, 0); | |
| 1210 | if (win >= phb->ioda.m64_bar_idx + 1) | 1227 | |
| 1211 | goto m64_failed; | 1228 | if (win >= phb->ioda.m64_bar_idx + 1) |
| 1212 | } while (test_and_set_bit(win, &phb->ioda.m64_bar_alloc)); | 1229 | goto m64_failed; |
| 1230 | } while (test_and_set_bit(win, &phb->ioda.m64_bar_alloc)); | ||
| 1231 | |||
| 1232 | pdn->m64_wins[i][j] = win; | ||
| 1233 | |||
| 1234 | if (pdn->m64_per_iov == M64_PER_IOV) { | ||
| 1235 | size = pci_iov_resource_size(pdev, | ||
| 1236 | PCI_IOV_RESOURCES + i); | ||
| 1237 | size = size * vf_per_group; | ||
| 1238 | start = res->start + size * j; | ||
| 1239 | } else { | ||
| 1240 | size = resource_size(res); | ||
| 1241 | start = res->start; | ||
| 1242 | } | ||
| 1213 | 1243 | ||
| 1214 | pdn->m64_wins[i] = win; | 1244 | /* Map the M64 here */ |
| 1245 | if (pdn->m64_per_iov == M64_PER_IOV) { | ||
| 1246 | pe_num = pdn->offset + j; | ||
| 1247 | rc = opal_pci_map_pe_mmio_window(phb->opal_id, | ||
| 1248 | pe_num, OPAL_M64_WINDOW_TYPE, | ||
| 1249 | pdn->m64_wins[i][j], 0); | ||
| 1250 | } | ||
| 1215 | 1251 | ||
| 1216 | /* Map the M64 here */ | 1252 | rc = opal_pci_set_phb_mem_window(phb->opal_id, |
| 1217 | rc = opal_pci_set_phb_mem_window(phb->opal_id, | ||
| 1218 | OPAL_M64_WINDOW_TYPE, | 1253 | OPAL_M64_WINDOW_TYPE, |
| 1219 | pdn->m64_wins[i], | 1254 | pdn->m64_wins[i][j], |
| 1220 | res->start, | 1255 | start, |
| 1221 | 0, /* unused */ | 1256 | 0, /* unused */ |
| 1222 | resource_size(res)); | 1257 | size); |
| 1223 | if (rc != OPAL_SUCCESS) { | ||
| 1224 | dev_err(&pdev->dev, "Failed to map M64 window #%d: %lld\n", | ||
| 1225 | win, rc); | ||
| 1226 | goto m64_failed; | ||
| 1227 | } | ||
| 1228 | 1258 | ||
| 1229 | rc = opal_pci_phb_mmio_enable(phb->opal_id, | 1259 | |
| 1230 | OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 1); | 1260 | if (rc != OPAL_SUCCESS) { |
| 1231 | if (rc != OPAL_SUCCESS) { | 1261 | dev_err(&pdev->dev, "Failed to map M64 window #%d: %lld\n", |
| 1232 | dev_err(&pdev->dev, "Failed to enable M64 window #%d: %llx\n", | 1262 | win, rc); |
| 1233 | win, rc); | 1263 | goto m64_failed; |
| 1234 | goto m64_failed; | 1264 | } |
| 1265 | |||
| 1266 | if (pdn->m64_per_iov == M64_PER_IOV) | ||
| 1267 | rc = opal_pci_phb_mmio_enable(phb->opal_id, | ||
| 1268 | OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 2); | ||
| 1269 | else | ||
| 1270 | rc = opal_pci_phb_mmio_enable(phb->opal_id, | ||
| 1271 | OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 1); | ||
| 1272 | |||
| 1273 | if (rc != OPAL_SUCCESS) { | ||
| 1274 | dev_err(&pdev->dev, "Failed to enable M64 window #%d: %llx\n", | ||
| 1275 | win, rc); | ||
| 1276 | goto m64_failed; | ||
| 1277 | } | ||
| 1235 | } | 1278 | } |
| 1236 | } | 1279 | } |
| 1237 | return 0; | 1280 | return 0; |
| @@ -1273,22 +1316,53 @@ static void pnv_pci_ioda2_release_dma_pe(struct pci_dev *dev, struct pnv_ioda_pe | |||
| 1273 | pe->tce32_table = NULL; | 1316 | pe->tce32_table = NULL; |
| 1274 | } | 1317 | } |
| 1275 | 1318 | ||
| 1276 | static void pnv_ioda_release_vf_PE(struct pci_dev *pdev) | 1319 | static void pnv_ioda_release_vf_PE(struct pci_dev *pdev, u16 num_vfs) |
| 1277 | { | 1320 | { |
| 1278 | struct pci_bus *bus; | 1321 | struct pci_bus *bus; |
| 1279 | struct pci_controller *hose; | 1322 | struct pci_controller *hose; |
| 1280 | struct pnv_phb *phb; | 1323 | struct pnv_phb *phb; |
| 1281 | struct pnv_ioda_pe *pe, *pe_n; | 1324 | struct pnv_ioda_pe *pe, *pe_n; |
| 1282 | struct pci_dn *pdn; | 1325 | struct pci_dn *pdn; |
| 1326 | u16 vf_index; | ||
| 1327 | int64_t rc; | ||
| 1283 | 1328 | ||
| 1284 | bus = pdev->bus; | 1329 | bus = pdev->bus; |
| 1285 | hose = pci_bus_to_host(bus); | 1330 | hose = pci_bus_to_host(bus); |
| 1286 | phb = hose->private_data; | 1331 | phb = hose->private_data; |
| 1332 | pdn = pci_get_pdn(pdev); | ||
| 1287 | 1333 | ||
| 1288 | if (!pdev->is_physfn) | 1334 | if (!pdev->is_physfn) |
| 1289 | return; | 1335 | return; |
| 1290 | 1336 | ||
| 1291 | pdn = pci_get_pdn(pdev); | 1337 | if (pdn->m64_per_iov == M64_PER_IOV && num_vfs > M64_PER_IOV) { |
| 1338 | int vf_group; | ||
| 1339 | int vf_per_group; | ||
| 1340 | int vf_index1; | ||
| 1341 | |||
| 1342 | vf_per_group = roundup_pow_of_two(num_vfs) / pdn->m64_per_iov; | ||
| 1343 | |||
| 1344 | for (vf_group = 0; vf_group < M64_PER_IOV; vf_group++) | ||
| 1345 | for (vf_index = vf_group * vf_per_group; | ||
| 1346 | vf_index < (vf_group + 1) * vf_per_group && | ||
| 1347 | vf_index < num_vfs; | ||
| 1348 | vf_index++) | ||
| 1349 | for (vf_index1 = vf_group * vf_per_group; | ||
| 1350 | vf_index1 < (vf_group + 1) * vf_per_group && | ||
| 1351 | vf_index1 < num_vfs; | ||
| 1352 | vf_index1++){ | ||
| 1353 | |||
| 1354 | rc = opal_pci_set_peltv(phb->opal_id, | ||
| 1355 | pdn->offset + vf_index, | ||
| 1356 | pdn->offset + vf_index1, | ||
| 1357 | OPAL_REMOVE_PE_FROM_DOMAIN); | ||
| 1358 | |||
| 1359 | if (rc) | ||
| 1360 | dev_warn(&pdev->dev, "%s: Failed to unlink same group PE#%d(%lld)\n", | ||
| 1361 | __func__, | ||
| 1362 | pdn->offset + vf_index1, rc); | ||
| 1363 | } | ||
| 1364 | } | ||
| 1365 | |||
| 1292 | list_for_each_entry_safe(pe, pe_n, &phb->ioda.pe_list, list) { | 1366 | list_for_each_entry_safe(pe, pe_n, &phb->ioda.pe_list, list) { |
| 1293 | if (pe->parent_dev != pdev) | 1367 | if (pe->parent_dev != pdev) |
| 1294 | continue; | 1368 | continue; |
| @@ -1323,10 +1397,11 @@ void pnv_pci_sriov_disable(struct pci_dev *pdev) | |||
| 1323 | num_vfs = pdn->num_vfs; | 1397 | num_vfs = pdn->num_vfs; |
| 1324 | 1398 | ||
| 1325 | /* Release VF PEs */ | 1399 | /* Release VF PEs */ |
| 1326 | pnv_ioda_release_vf_PE(pdev); | 1400 | pnv_ioda_release_vf_PE(pdev, num_vfs); |
| 1327 | 1401 | ||
| 1328 | if (phb->type == PNV_PHB_IODA2) { | 1402 | if (phb->type == PNV_PHB_IODA2) { |
| 1329 | pnv_pci_vf_resource_shift(pdev, -pdn->offset); | 1403 | if (pdn->m64_per_iov == 1) |
| 1404 | pnv_pci_vf_resource_shift(pdev, -pdn->offset); | ||
| 1330 | 1405 | ||
| 1331 | /* Release M64 windows */ | 1406 | /* Release M64 windows */ |
| 1332 | pnv_pci_vf_release_m64(pdev); | 1407 | pnv_pci_vf_release_m64(pdev); |
| @@ -1348,6 +1423,7 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs) | |||
| 1348 | int pe_num; | 1423 | int pe_num; |
| 1349 | u16 vf_index; | 1424 | u16 vf_index; |
| 1350 | struct pci_dn *pdn; | 1425 | struct pci_dn *pdn; |
| 1426 | int64_t rc; | ||
| 1351 | 1427 | ||
| 1352 | bus = pdev->bus; | 1428 | bus = pdev->bus; |
| 1353 | hose = pci_bus_to_host(bus); | 1429 | hose = pci_bus_to_host(bus); |
| @@ -1396,6 +1472,37 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs) | |||
| 1396 | 1472 | ||
| 1397 | pnv_pci_ioda2_setup_dma_pe(phb, pe); | 1473 | pnv_pci_ioda2_setup_dma_pe(phb, pe); |
| 1398 | } | 1474 | } |
| 1475 | |||
| 1476 | if (pdn->m64_per_iov == M64_PER_IOV && num_vfs > M64_PER_IOV) { | ||
| 1477 | int vf_group; | ||
| 1478 | int vf_per_group; | ||
| 1479 | int vf_index1; | ||
| 1480 | |||
| 1481 | vf_per_group = roundup_pow_of_two(num_vfs) / pdn->m64_per_iov; | ||
| 1482 | |||
| 1483 | for (vf_group = 0; vf_group < M64_PER_IOV; vf_group++) { | ||
| 1484 | for (vf_index = vf_group * vf_per_group; | ||
| 1485 | vf_index < (vf_group + 1) * vf_per_group && | ||
| 1486 | vf_index < num_vfs; | ||
| 1487 | vf_index++) { | ||
| 1488 | for (vf_index1 = vf_group * vf_per_group; | ||
| 1489 | vf_index1 < (vf_group + 1) * vf_per_group && | ||
| 1490 | vf_index1 < num_vfs; | ||
| 1491 | vf_index1++) { | ||
| 1492 | |||
| 1493 | rc = opal_pci_set_peltv(phb->opal_id, | ||
| 1494 | pdn->offset + vf_index, | ||
| 1495 | pdn->offset + vf_index1, | ||
| 1496 | OPAL_ADD_PE_TO_DOMAIN); | ||
| 1497 | |||
| 1498 | if (rc) | ||
| 1499 | dev_warn(&pdev->dev, "%s: Failed to link same group PE#%d(%lld)\n", | ||
| 1500 | __func__, | ||
| 1501 | pdn->offset + vf_index1, rc); | ||
| 1502 | } | ||
| 1503 | } | ||
| 1504 | } | ||
| 1505 | } | ||
| 1399 | } | 1506 | } |
| 1400 | 1507 | ||
| 1401 | int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) | 1508 | int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) |
| @@ -1428,7 +1535,7 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) | |||
| 1428 | mutex_unlock(&phb->ioda.pe_alloc_mutex); | 1535 | mutex_unlock(&phb->ioda.pe_alloc_mutex); |
| 1429 | 1536 | ||
| 1430 | /* Assign M64 window accordingly */ | 1537 | /* Assign M64 window accordingly */ |
| 1431 | ret = pnv_pci_vf_assign_m64(pdev); | 1538 | ret = pnv_pci_vf_assign_m64(pdev, num_vfs); |
| 1432 | if (ret) { | 1539 | if (ret) { |
| 1433 | dev_info(&pdev->dev, "Not enough M64 window resources\n"); | 1540 | dev_info(&pdev->dev, "Not enough M64 window resources\n"); |
| 1434 | goto m64_failed; | 1541 | goto m64_failed; |
| @@ -1439,9 +1546,11 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) | |||
| 1439 | * the IOV BAR according to the PE# allocated to the VFs. | 1546 | * the IOV BAR according to the PE# allocated to the VFs. |
| 1440 | * Otherwise, the PE# for the VF will conflict with others. | 1547 | * Otherwise, the PE# for the VF will conflict with others. |
| 1441 | */ | 1548 | */ |
| 1442 | ret = pnv_pci_vf_resource_shift(pdev, pdn->offset); | 1549 | if (pdn->m64_per_iov == 1) { |
| 1443 | if (ret) | 1550 | ret = pnv_pci_vf_resource_shift(pdev, pdn->offset); |
| 1444 | goto m64_failed; | 1551 | if (ret) |
| 1552 | goto m64_failed; | ||
| 1553 | } | ||
| 1445 | } | 1554 | } |
| 1446 | 1555 | ||
| 1447 | /* Setup VF PEs */ | 1556 | /* Setup VF PEs */ |
