diff options
| -rw-r--r-- | drivers/pci/msi.c | 150 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 2 | ||||
| -rw-r--r-- | include/linux/msi.h | 8 | ||||
| -rw-r--r-- | include/linux/pci_regs.h | 1 |
5 files changed, 29 insertions, 134 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 01869b1782e4..ad33e0159514 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
| @@ -100,6 +100,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag) | |||
| 100 | BUG(); | 100 | BUG(); |
| 101 | break; | 101 | break; |
| 102 | } | 102 | } |
| 103 | entry->msi_attrib.masked = !!flag; | ||
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | 106 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
| @@ -179,6 +180,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
| 179 | default: | 180 | default: |
| 180 | BUG(); | 181 | BUG(); |
| 181 | } | 182 | } |
| 183 | entry->msg = *msg; | ||
| 182 | } | 184 | } |
| 183 | 185 | ||
| 184 | void mask_msi_irq(unsigned int irq) | 186 | void mask_msi_irq(unsigned int irq) |
| @@ -225,164 +227,60 @@ static struct msi_desc* alloc_msi_entry(void) | |||
| 225 | } | 227 | } |
| 226 | 228 | ||
| 227 | #ifdef CONFIG_PM | 229 | #ifdef CONFIG_PM |
| 228 | static int __pci_save_msi_state(struct pci_dev *dev) | ||
| 229 | { | ||
| 230 | int pos, i = 0; | ||
| 231 | u16 control; | ||
| 232 | struct pci_cap_saved_state *save_state; | ||
| 233 | u32 *cap; | ||
| 234 | |||
| 235 | if (!dev->msi_enabled) | ||
| 236 | return 0; | ||
| 237 | |||
| 238 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
| 239 | if (pos <= 0) | ||
| 240 | return 0; | ||
| 241 | |||
| 242 | save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, | ||
| 243 | GFP_KERNEL); | ||
| 244 | if (!save_state) { | ||
| 245 | printk(KERN_ERR "Out of memory in pci_save_msi_state\n"); | ||
| 246 | return -ENOMEM; | ||
| 247 | } | ||
| 248 | cap = &save_state->data[0]; | ||
| 249 | |||
| 250 | pci_read_config_dword(dev, pos, &cap[i++]); | ||
| 251 | control = cap[0] >> 16; | ||
| 252 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]); | ||
| 253 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
| 254 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]); | ||
| 255 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]); | ||
| 256 | } else | ||
| 257 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | ||
| 258 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
| 259 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | ||
| 260 | save_state->cap_nr = PCI_CAP_ID_MSI; | ||
| 261 | pci_add_saved_cap(dev, save_state); | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static void __pci_restore_msi_state(struct pci_dev *dev) | 230 | static void __pci_restore_msi_state(struct pci_dev *dev) |
| 266 | { | 231 | { |
| 267 | int i = 0, pos; | 232 | int pos; |
| 268 | u16 control; | 233 | u16 control; |
| 269 | struct pci_cap_saved_state *save_state; | 234 | struct msi_desc *entry; |
| 270 | u32 *cap; | ||
| 271 | 235 | ||
| 272 | if (!dev->msi_enabled) | 236 | if (!dev->msi_enabled) |
| 273 | return; | 237 | return; |
| 274 | 238 | ||
| 275 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); | 239 | entry = get_irq_msi(dev->irq); |
| 276 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 240 | pos = entry->msi_attrib.pos; |
| 277 | if (!save_state || pos <= 0) | ||
| 278 | return; | ||
| 279 | cap = &save_state->data[0]; | ||
| 280 | 241 | ||
| 281 | pci_intx(dev, 0); /* disable intx */ | 242 | pci_intx(dev, 0); /* disable intx */ |
| 282 | control = cap[i++] >> 16; | ||
| 283 | msi_set_enable(dev, 0); | 243 | msi_set_enable(dev, 0); |
| 284 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); | 244 | write_msi_msg(dev->irq, &entry->msg); |
| 285 | if (control & PCI_MSI_FLAGS_64BIT) { | 245 | if (entry->msi_attrib.maskbit) |
| 286 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); | 246 | msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); |
| 287 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]); | 247 | |
| 288 | } else | 248 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); |
| 289 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]); | 249 | control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); |
| 290 | if (control & PCI_MSI_FLAGS_MASKBIT) | 250 | if (entry->msi_attrib.maskbit || !entry->msi_attrib.masked) |
| 291 | pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); | 251 | control |= PCI_MSI_FLAGS_ENABLE; |
| 292 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | 252 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); |
| 293 | pci_remove_saved_cap(save_state); | ||
| 294 | kfree(save_state); | ||
| 295 | } | ||
| 296 | |||
| 297 | static int __pci_save_msix_state(struct pci_dev *dev) | ||
| 298 | { | ||
| 299 | int pos; | ||
| 300 | int irq, head, tail = 0; | ||
| 301 | u16 control; | ||
| 302 | struct pci_cap_saved_state *save_state; | ||
| 303 | |||
| 304 | if (!dev->msix_enabled) | ||
| 305 | return 0; | ||
| 306 | |||
| 307 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 308 | if (pos <= 0) | ||
| 309 | return 0; | ||
| 310 | |||
| 311 | /* save the capability */ | ||
| 312 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 313 | save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), | ||
| 314 | GFP_KERNEL); | ||
| 315 | if (!save_state) { | ||
| 316 | printk(KERN_ERR "Out of memory in pci_save_msix_state\n"); | ||
| 317 | return -ENOMEM; | ||
| 318 | } | ||
| 319 | *((u16 *)&save_state->data[0]) = control; | ||
| 320 | |||
| 321 | /* save the table */ | ||
| 322 | irq = head = dev->first_msi_irq; | ||
| 323 | while (head != tail) { | ||
| 324 | struct msi_desc *entry; | ||
| 325 | |||
| 326 | entry = get_irq_msi(irq); | ||
| 327 | read_msi_msg(irq, &entry->msg_save); | ||
| 328 | |||
| 329 | tail = entry->link.tail; | ||
| 330 | irq = tail; | ||
| 331 | } | ||
| 332 | |||
| 333 | save_state->cap_nr = PCI_CAP_ID_MSIX; | ||
| 334 | pci_add_saved_cap(dev, save_state); | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | int pci_save_msi_state(struct pci_dev *dev) | ||
| 339 | { | ||
| 340 | int rc; | ||
| 341 | |||
| 342 | rc = __pci_save_msi_state(dev); | ||
| 343 | if (rc) | ||
| 344 | return rc; | ||
| 345 | |||
| 346 | rc = __pci_save_msix_state(dev); | ||
| 347 | |||
| 348 | return rc; | ||
| 349 | } | 253 | } |
| 350 | 254 | ||
| 351 | static void __pci_restore_msix_state(struct pci_dev *dev) | 255 | static void __pci_restore_msix_state(struct pci_dev *dev) |
| 352 | { | 256 | { |
| 353 | u16 save; | ||
| 354 | int pos; | 257 | int pos; |
| 355 | int irq, head, tail = 0; | 258 | int irq, head, tail = 0; |
| 356 | struct msi_desc *entry; | 259 | struct msi_desc *entry; |
| 357 | struct pci_cap_saved_state *save_state; | 260 | u16 control; |
| 358 | 261 | ||
| 359 | if (!dev->msix_enabled) | 262 | if (!dev->msix_enabled) |
| 360 | return; | 263 | return; |
| 361 | 264 | ||
| 362 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); | ||
| 363 | if (!save_state) | ||
| 364 | return; | ||
| 365 | save = *((u16 *)&save_state->data[0]); | ||
| 366 | pci_remove_saved_cap(save_state); | ||
| 367 | kfree(save_state); | ||
| 368 | |||
| 369 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 370 | if (pos <= 0) | ||
| 371 | return; | ||
| 372 | |||
| 373 | /* route the table */ | 265 | /* route the table */ |
| 374 | pci_intx(dev, 0); /* disable intx */ | 266 | pci_intx(dev, 0); /* disable intx */ |
| 375 | msix_set_enable(dev, 0); | 267 | msix_set_enable(dev, 0); |
| 376 | irq = head = dev->first_msi_irq; | 268 | irq = head = dev->first_msi_irq; |
| 269 | entry = get_irq_msi(irq); | ||
| 270 | pos = entry->msi_attrib.pos; | ||
| 377 | while (head != tail) { | 271 | while (head != tail) { |
| 378 | entry = get_irq_msi(irq); | 272 | entry = get_irq_msi(irq); |
| 379 | write_msi_msg(irq, &entry->msg_save); | 273 | write_msi_msg(irq, &entry->msg); |
| 274 | msi_set_mask_bit(irq, entry->msi_attrib.masked); | ||
| 380 | 275 | ||
| 381 | tail = entry->link.tail; | 276 | tail = entry->link.tail; |
| 382 | irq = tail; | 277 | irq = tail; |
| 383 | } | 278 | } |
| 384 | 279 | ||
| 385 | pci_write_config_word(dev, msi_control_reg(pos), save); | 280 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); |
| 281 | control &= ~PCI_MSIX_FLAGS_MASKALL; | ||
| 282 | control |= PCI_MSIX_FLAGS_ENABLE; | ||
| 283 | pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); | ||
| 386 | } | 284 | } |
| 387 | 285 | ||
| 388 | void pci_restore_msi_state(struct pci_dev *dev) | 286 | void pci_restore_msi_state(struct pci_dev *dev) |
| @@ -420,6 +318,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
| 420 | entry->msi_attrib.is_64 = is_64bit_address(control); | 318 | entry->msi_attrib.is_64 = is_64bit_address(control); |
| 421 | entry->msi_attrib.entry_nr = 0; | 319 | entry->msi_attrib.entry_nr = 0; |
| 422 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 320 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
| 321 | entry->msi_attrib.masked = 1; | ||
| 423 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 322 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
| 424 | entry->msi_attrib.pos = pos; | 323 | entry->msi_attrib.pos = pos; |
| 425 | if (is_mask_bit_support(control)) { | 324 | if (is_mask_bit_support(control)) { |
| @@ -507,6 +406,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 507 | entry->msi_attrib.is_64 = 1; | 406 | entry->msi_attrib.is_64 = 1; |
| 508 | entry->msi_attrib.entry_nr = j; | 407 | entry->msi_attrib.entry_nr = j; |
| 509 | entry->msi_attrib.maskbit = 1; | 408 | entry->msi_attrib.maskbit = 1; |
| 409 | entry->msi_attrib.masked = 1; | ||
| 510 | entry->msi_attrib.default_irq = dev->irq; | 410 | entry->msi_attrib.default_irq = dev->irq; |
| 511 | entry->msi_attrib.pos = pos; | 411 | entry->msi_attrib.pos = pos; |
| 512 | entry->dev = dev; | 412 | entry->dev = dev; |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a32db0628157..6048c0c637a0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -638,8 +638,6 @@ pci_save_state(struct pci_dev *dev) | |||
| 638 | /* XXX: 100% dword access ok here? */ | 638 | /* XXX: 100% dword access ok here? */ |
| 639 | for (i = 0; i < 16; i++) | 639 | for (i = 0; i < 16; i++) |
| 640 | pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); | 640 | pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); |
| 641 | if ((i = pci_save_msi_state(dev)) != 0) | ||
| 642 | return i; | ||
| 643 | if ((i = pci_save_pcie_state(dev)) != 0) | 641 | if ((i = pci_save_pcie_state(dev)) != 0) |
| 644 | return i; | 642 | return i; |
| 645 | if ((i = pci_save_pcix_state(dev)) != 0) | 643 | if ((i = pci_save_pcix_state(dev)) != 0) |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index ae7a975995a5..62ea04c8af64 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -52,10 +52,8 @@ static inline void pci_no_msi(void) { } | |||
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) | 54 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) |
| 55 | int pci_save_msi_state(struct pci_dev *dev); | ||
| 56 | void pci_restore_msi_state(struct pci_dev *dev); | 55 | void pci_restore_msi_state(struct pci_dev *dev); |
| 57 | #else | 56 | #else |
| 58 | static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } | ||
| 59 | static inline void pci_restore_msi_state(struct pci_dev *dev) {} | 57 | static inline void pci_restore_msi_state(struct pci_dev *dev) {} |
| 60 | #endif | 58 | #endif |
| 61 | 59 | ||
diff --git a/include/linux/msi.h b/include/linux/msi.h index 74c8a2ecc9dd..e38fe6822cb4 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h | |||
| @@ -17,7 +17,7 @@ struct msi_desc { | |||
| 17 | struct { | 17 | struct { |
| 18 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 18 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
| 19 | __u8 maskbit : 1; /* mask-pending bit supported ? */ | 19 | __u8 maskbit : 1; /* mask-pending bit supported ? */ |
| 20 | __u8 unused : 1; | 20 | __u8 masked : 1; |
| 21 | __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ | 21 | __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ |
| 22 | __u8 pos; /* Location of the msi capability */ | 22 | __u8 pos; /* Location of the msi capability */ |
| 23 | __u16 entry_nr; /* specific enabled entry */ | 23 | __u16 entry_nr; /* specific enabled entry */ |
| @@ -32,10 +32,8 @@ struct msi_desc { | |||
| 32 | void __iomem *mask_base; | 32 | void __iomem *mask_base; |
| 33 | struct pci_dev *dev; | 33 | struct pci_dev *dev; |
| 34 | 34 | ||
| 35 | #ifdef CONFIG_PM | 35 | /* Last set MSI message */ |
| 36 | /* PM save area for MSIX address/data */ | 36 | struct msi_msg msg; |
| 37 | struct msi_msg msg_save; | ||
| 38 | #endif | ||
| 39 | }; | 37 | }; |
| 40 | 38 | ||
| 41 | /* | 39 | /* |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index f09cce2357ff..495d368390e0 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
| @@ -296,6 +296,7 @@ | |||
| 296 | #define PCI_MSIX_FLAGS 2 | 296 | #define PCI_MSIX_FLAGS 2 |
| 297 | #define PCI_MSIX_FLAGS_QSIZE 0x7FF | 297 | #define PCI_MSIX_FLAGS_QSIZE 0x7FF |
| 298 | #define PCI_MSIX_FLAGS_ENABLE (1 << 15) | 298 | #define PCI_MSIX_FLAGS_ENABLE (1 << 15) |
| 299 | #define PCI_MSIX_FLAGS_MASKALL (1 << 14) | ||
| 299 | #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) | 300 | #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) |
| 300 | #define PCI_MSIX_FLAGS_BITMASK (1 << 0) | 301 | #define PCI_MSIX_FLAGS_BITMASK (1 << 0) |
| 301 | 302 | ||
