aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h2
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c197
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
1178static int pnv_pci_vf_assign_m64(struct pci_dev *pdev) 1179static 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
1276static void pnv_ioda_release_vf_PE(struct pci_dev *pdev) 1319static 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
1401int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) 1508int 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 */