Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * CompactPCI Hot Plug Driver PCI functions
0004  *
0005  * Copyright (C) 2002,2005 by SOMA Networks, Inc.
0006  *
0007  * All rights reserved.
0008  *
0009  * Send feedback to <scottm@somanetworks.com>
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/pci.h>
0015 #include <linux/pci_hotplug.h>
0016 #include <linux/proc_fs.h>
0017 #include "../pci.h"
0018 #include "cpci_hotplug.h"
0019 
0020 #define MY_NAME "cpci_hotplug"
0021 
0022 #define dbg(format, arg...)                 \
0023     do {                            \
0024         if (cpci_debug)                 \
0025             printk(KERN_DEBUG "%s: " format "\n",   \
0026                 MY_NAME, ## arg);       \
0027     } while (0)
0028 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
0029 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
0030 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
0031 
0032 
0033 u8 cpci_get_attention_status(struct slot *slot)
0034 {
0035     int hs_cap;
0036     u16 hs_csr;
0037 
0038     hs_cap = pci_bus_find_capability(slot->bus,
0039                      slot->devfn,
0040                      PCI_CAP_ID_CHSWP);
0041     if (!hs_cap)
0042         return 0;
0043 
0044     if (pci_bus_read_config_word(slot->bus,
0045                      slot->devfn,
0046                      hs_cap + 2,
0047                      &hs_csr))
0048         return 0;
0049 
0050     return hs_csr & 0x0008 ? 1 : 0;
0051 }
0052 
0053 int cpci_set_attention_status(struct slot *slot, int status)
0054 {
0055     int hs_cap;
0056     u16 hs_csr;
0057 
0058     hs_cap = pci_bus_find_capability(slot->bus,
0059                      slot->devfn,
0060                      PCI_CAP_ID_CHSWP);
0061     if (!hs_cap)
0062         return 0;
0063     if (pci_bus_read_config_word(slot->bus,
0064                      slot->devfn,
0065                      hs_cap + 2,
0066                      &hs_csr))
0067         return 0;
0068     if (status)
0069         hs_csr |= HS_CSR_LOO;
0070     else
0071         hs_csr &= ~HS_CSR_LOO;
0072     if (pci_bus_write_config_word(slot->bus,
0073                       slot->devfn,
0074                       hs_cap + 2,
0075                       hs_csr))
0076         return 0;
0077     return 1;
0078 }
0079 
0080 u16 cpci_get_hs_csr(struct slot *slot)
0081 {
0082     int hs_cap;
0083     u16 hs_csr;
0084 
0085     hs_cap = pci_bus_find_capability(slot->bus,
0086                      slot->devfn,
0087                      PCI_CAP_ID_CHSWP);
0088     if (!hs_cap)
0089         return 0xFFFF;
0090     if (pci_bus_read_config_word(slot->bus,
0091                      slot->devfn,
0092                      hs_cap + 2,
0093                      &hs_csr))
0094         return 0xFFFF;
0095     return hs_csr;
0096 }
0097 
0098 int cpci_check_and_clear_ins(struct slot *slot)
0099 {
0100     int hs_cap;
0101     u16 hs_csr;
0102     int ins = 0;
0103 
0104     hs_cap = pci_bus_find_capability(slot->bus,
0105                      slot->devfn,
0106                      PCI_CAP_ID_CHSWP);
0107     if (!hs_cap)
0108         return 0;
0109     if (pci_bus_read_config_word(slot->bus,
0110                      slot->devfn,
0111                      hs_cap + 2,
0112                      &hs_csr))
0113         return 0;
0114     if (hs_csr & HS_CSR_INS) {
0115         /* Clear INS (by setting it) */
0116         if (pci_bus_write_config_word(slot->bus,
0117                           slot->devfn,
0118                           hs_cap + 2,
0119                           hs_csr))
0120             ins = 0;
0121         else
0122             ins = 1;
0123     }
0124     return ins;
0125 }
0126 
0127 int cpci_check_ext(struct slot *slot)
0128 {
0129     int hs_cap;
0130     u16 hs_csr;
0131     int ext = 0;
0132 
0133     hs_cap = pci_bus_find_capability(slot->bus,
0134                      slot->devfn,
0135                      PCI_CAP_ID_CHSWP);
0136     if (!hs_cap)
0137         return 0;
0138     if (pci_bus_read_config_word(slot->bus,
0139                      slot->devfn,
0140                      hs_cap + 2,
0141                      &hs_csr))
0142         return 0;
0143     if (hs_csr & HS_CSR_EXT)
0144         ext = 1;
0145     return ext;
0146 }
0147 
0148 int cpci_clear_ext(struct slot *slot)
0149 {
0150     int hs_cap;
0151     u16 hs_csr;
0152 
0153     hs_cap = pci_bus_find_capability(slot->bus,
0154                      slot->devfn,
0155                      PCI_CAP_ID_CHSWP);
0156     if (!hs_cap)
0157         return -ENODEV;
0158     if (pci_bus_read_config_word(slot->bus,
0159                      slot->devfn,
0160                      hs_cap + 2,
0161                      &hs_csr))
0162         return -ENODEV;
0163     if (hs_csr & HS_CSR_EXT) {
0164         /* Clear EXT (by setting it) */
0165         if (pci_bus_write_config_word(slot->bus,
0166                           slot->devfn,
0167                           hs_cap + 2,
0168                           hs_csr))
0169             return -ENODEV;
0170     }
0171     return 0;
0172 }
0173 
0174 int cpci_led_on(struct slot *slot)
0175 {
0176     int hs_cap;
0177     u16 hs_csr;
0178 
0179     hs_cap = pci_bus_find_capability(slot->bus,
0180                      slot->devfn,
0181                      PCI_CAP_ID_CHSWP);
0182     if (!hs_cap)
0183         return -ENODEV;
0184     if (pci_bus_read_config_word(slot->bus,
0185                      slot->devfn,
0186                      hs_cap + 2,
0187                      &hs_csr))
0188         return -ENODEV;
0189     if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
0190         hs_csr |= HS_CSR_LOO;
0191         if (pci_bus_write_config_word(slot->bus,
0192                           slot->devfn,
0193                           hs_cap + 2,
0194                           hs_csr)) {
0195             err("Could not set LOO for slot %s", slot_name(slot));
0196             return -ENODEV;
0197         }
0198     }
0199     return 0;
0200 }
0201 
0202 int cpci_led_off(struct slot *slot)
0203 {
0204     int hs_cap;
0205     u16 hs_csr;
0206 
0207     hs_cap = pci_bus_find_capability(slot->bus,
0208                      slot->devfn,
0209                      PCI_CAP_ID_CHSWP);
0210     if (!hs_cap)
0211         return -ENODEV;
0212     if (pci_bus_read_config_word(slot->bus,
0213                      slot->devfn,
0214                      hs_cap + 2,
0215                      &hs_csr))
0216         return -ENODEV;
0217     if (hs_csr & HS_CSR_LOO) {
0218         hs_csr &= ~HS_CSR_LOO;
0219         if (pci_bus_write_config_word(slot->bus,
0220                           slot->devfn,
0221                           hs_cap + 2,
0222                           hs_csr)) {
0223             err("Could not clear LOO for slot %s", slot_name(slot));
0224             return -ENODEV;
0225         }
0226     }
0227     return 0;
0228 }
0229 
0230 
0231 /*
0232  * Device configuration functions
0233  */
0234 
0235 int cpci_configure_slot(struct slot *slot)
0236 {
0237     struct pci_dev *dev;
0238     struct pci_bus *parent;
0239     int ret = 0;
0240 
0241     dbg("%s - enter", __func__);
0242 
0243     pci_lock_rescan_remove();
0244 
0245     if (slot->dev == NULL) {
0246         dbg("pci_dev null, finding %02x:%02x:%x",
0247             slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
0248         slot->dev = pci_get_slot(slot->bus, slot->devfn);
0249     }
0250 
0251     /* Still NULL? Well then scan for it! */
0252     if (slot->dev == NULL) {
0253         int n;
0254         dbg("pci_dev still null");
0255 
0256         /*
0257          * This will generate pci_dev structures for all functions, but
0258          * we will only call this case when lookup fails.
0259          */
0260         n = pci_scan_slot(slot->bus, slot->devfn);
0261         dbg("%s: pci_scan_slot returned %d", __func__, n);
0262         slot->dev = pci_get_slot(slot->bus, slot->devfn);
0263         if (slot->dev == NULL) {
0264             err("Could not find PCI device for slot %02x", slot->number);
0265             ret = -ENODEV;
0266             goto out;
0267         }
0268     }
0269     parent = slot->dev->bus;
0270 
0271     for_each_pci_bridge(dev, parent) {
0272         if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))
0273             pci_hp_add_bridge(dev);
0274     }
0275 
0276     pci_assign_unassigned_bridge_resources(parent->self);
0277 
0278     pci_bus_add_devices(parent);
0279 
0280  out:
0281     pci_unlock_rescan_remove();
0282     dbg("%s - exit", __func__);
0283     return ret;
0284 }
0285 
0286 int cpci_unconfigure_slot(struct slot *slot)
0287 {
0288     struct pci_dev *dev, *temp;
0289 
0290     dbg("%s - enter", __func__);
0291     if (!slot->dev) {
0292         err("No device for slot %02x\n", slot->number);
0293         return -ENODEV;
0294     }
0295 
0296     pci_lock_rescan_remove();
0297 
0298     list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
0299         if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
0300             continue;
0301         pci_dev_get(dev);
0302         pci_stop_and_remove_bus_device(dev);
0303         pci_dev_put(dev);
0304     }
0305     pci_dev_put(slot->dev);
0306     slot->dev = NULL;
0307 
0308     pci_unlock_rescan_remove();
0309 
0310     dbg("%s - exit", __func__);
0311     return 0;
0312 }