brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 6c48066 Raw
313 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * CompactPCI Hot Plug Driver PCI functions4 *5 * Copyright (C) 2002,2005 by SOMA Networks, Inc.6 *7 * All rights reserved.8 *9 * Send feedback to <scottm@somanetworks.com>10 */11 12#include <linux/module.h>13#include <linux/kernel.h>14#include <linux/pci.h>15#include <linux/pci_hotplug.h>16#include <linux/proc_fs.h>17#include "../pci.h"18#include "cpci_hotplug.h"19 20#define MY_NAME	"cpci_hotplug"21 22#define dbg(format, arg...)					\23	do {							\24		if (cpci_debug)					\25			printk(KERN_DEBUG "%s: " format "\n",	\26				MY_NAME, ## arg);		\27	} while (0)28#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)29#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)30#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)31 32 33u8 cpci_get_attention_status(struct slot *slot)34{35	int hs_cap;36	u16 hs_csr;37 38	hs_cap = pci_bus_find_capability(slot->bus,39					 slot->devfn,40					 PCI_CAP_ID_CHSWP);41	if (!hs_cap)42		return 0;43 44	if (pci_bus_read_config_word(slot->bus,45				     slot->devfn,46				     hs_cap + 2,47				     &hs_csr))48		return 0;49 50	return hs_csr & 0x0008 ? 1 : 0;51}52 53int cpci_set_attention_status(struct slot *slot, int status)54{55	int hs_cap;56	u16 hs_csr;57 58	hs_cap = pci_bus_find_capability(slot->bus,59					 slot->devfn,60					 PCI_CAP_ID_CHSWP);61	if (!hs_cap)62		return 0;63	if (pci_bus_read_config_word(slot->bus,64				     slot->devfn,65				     hs_cap + 2,66				     &hs_csr))67		return 0;68	if (status)69		hs_csr |= HS_CSR_LOO;70	else71		hs_csr &= ~HS_CSR_LOO;72	if (pci_bus_write_config_word(slot->bus,73				      slot->devfn,74				      hs_cap + 2,75				      hs_csr))76		return 0;77	return 1;78}79 80u16 cpci_get_hs_csr(struct slot *slot)81{82	int hs_cap;83	u16 hs_csr;84 85	hs_cap = pci_bus_find_capability(slot->bus,86					 slot->devfn,87					 PCI_CAP_ID_CHSWP);88	if (!hs_cap)89		return 0xFFFF;90	if (pci_bus_read_config_word(slot->bus,91				     slot->devfn,92				     hs_cap + 2,93				     &hs_csr))94		return 0xFFFF;95	return hs_csr;96}97 98int cpci_check_and_clear_ins(struct slot *slot)99{100	int hs_cap;101	u16 hs_csr;102	int ins = 0;103 104	hs_cap = pci_bus_find_capability(slot->bus,105					 slot->devfn,106					 PCI_CAP_ID_CHSWP);107	if (!hs_cap)108		return 0;109	if (pci_bus_read_config_word(slot->bus,110				     slot->devfn,111				     hs_cap + 2,112				     &hs_csr))113		return 0;114	if (hs_csr & HS_CSR_INS) {115		/* Clear INS (by setting it) */116		if (pci_bus_write_config_word(slot->bus,117					      slot->devfn,118					      hs_cap + 2,119					      hs_csr))120			ins = 0;121		else122			ins = 1;123	}124	return ins;125}126 127int cpci_check_ext(struct slot *slot)128{129	int hs_cap;130	u16 hs_csr;131	int ext = 0;132 133	hs_cap = pci_bus_find_capability(slot->bus,134					 slot->devfn,135					 PCI_CAP_ID_CHSWP);136	if (!hs_cap)137		return 0;138	if (pci_bus_read_config_word(slot->bus,139				     slot->devfn,140				     hs_cap + 2,141				     &hs_csr))142		return 0;143	if (hs_csr & HS_CSR_EXT)144		ext = 1;145	return ext;146}147 148int cpci_clear_ext(struct slot *slot)149{150	int hs_cap;151	u16 hs_csr;152 153	hs_cap = pci_bus_find_capability(slot->bus,154					 slot->devfn,155					 PCI_CAP_ID_CHSWP);156	if (!hs_cap)157		return -ENODEV;158	if (pci_bus_read_config_word(slot->bus,159				     slot->devfn,160				     hs_cap + 2,161				     &hs_csr))162		return -ENODEV;163	if (hs_csr & HS_CSR_EXT) {164		/* Clear EXT (by setting it) */165		if (pci_bus_write_config_word(slot->bus,166					      slot->devfn,167					      hs_cap + 2,168					      hs_csr))169			return -ENODEV;170	}171	return 0;172}173 174int cpci_led_on(struct slot *slot)175{176	int hs_cap;177	u16 hs_csr;178 179	hs_cap = pci_bus_find_capability(slot->bus,180					 slot->devfn,181					 PCI_CAP_ID_CHSWP);182	if (!hs_cap)183		return -ENODEV;184	if (pci_bus_read_config_word(slot->bus,185				     slot->devfn,186				     hs_cap + 2,187				     &hs_csr))188		return -ENODEV;189	if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {190		hs_csr |= HS_CSR_LOO;191		if (pci_bus_write_config_word(slot->bus,192					      slot->devfn,193					      hs_cap + 2,194					      hs_csr)) {195			err("Could not set LOO for slot %s", slot_name(slot));196			return -ENODEV;197		}198	}199	return 0;200}201 202int cpci_led_off(struct slot *slot)203{204	int hs_cap;205	u16 hs_csr;206 207	hs_cap = pci_bus_find_capability(slot->bus,208					 slot->devfn,209					 PCI_CAP_ID_CHSWP);210	if (!hs_cap)211		return -ENODEV;212	if (pci_bus_read_config_word(slot->bus,213				     slot->devfn,214				     hs_cap + 2,215				     &hs_csr))216		return -ENODEV;217	if (hs_csr & HS_CSR_LOO) {218		hs_csr &= ~HS_CSR_LOO;219		if (pci_bus_write_config_word(slot->bus,220					      slot->devfn,221					      hs_cap + 2,222					      hs_csr)) {223			err("Could not clear LOO for slot %s", slot_name(slot));224			return -ENODEV;225		}226	}227	return 0;228}229 230 231/*232 * Device configuration functions233 */234 235int cpci_configure_slot(struct slot *slot)236{237	struct pci_dev *dev;238	struct pci_bus *parent;239	int ret = 0;240 241	dbg("%s - enter", __func__);242 243	pci_lock_rescan_remove();244 245	if (slot->dev == NULL) {246		dbg("pci_dev null, finding %02x:%02x:%x",247		    slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));248		slot->dev = pci_get_slot(slot->bus, slot->devfn);249	}250 251	/* Still NULL? Well then scan for it! */252	if (slot->dev == NULL) {253		int n;254		dbg("pci_dev still null");255 256		/*257		 * This will generate pci_dev structures for all functions, but258		 * we will only call this case when lookup fails.259		 */260		n = pci_scan_slot(slot->bus, slot->devfn);261		dbg("%s: pci_scan_slot returned %d", __func__, n);262		slot->dev = pci_get_slot(slot->bus, slot->devfn);263		if (slot->dev == NULL) {264			err("Could not find PCI device for slot %02x", slot->number);265			ret = -ENODEV;266			goto out;267		}268	}269	parent = slot->dev->bus;270 271	for_each_pci_bridge(dev, parent) {272		if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))273			pci_hp_add_bridge(dev);274	}275 276	pci_assign_unassigned_bridge_resources(parent->self);277 278	pci_bus_add_devices(parent);279 280 out:281	pci_unlock_rescan_remove();282	dbg("%s - exit", __func__);283	return ret;284}285 286int cpci_unconfigure_slot(struct slot *slot)287{288	struct pci_dev *dev, *temp;289 290	dbg("%s - enter", __func__);291	if (!slot->dev) {292		err("No device for slot %02x\n", slot->number);293		return -ENODEV;294	}295 296	pci_lock_rescan_remove();297 298	list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {299		if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))300			continue;301		pci_dev_get(dev);302		pci_stop_and_remove_bus_device(dev);303		pci_dev_put(dev);304	}305	pci_dev_put(slot->dev);306	slot->dev = NULL;307 308	pci_unlock_rescan_remove();309 310	dbg("%s - exit", __func__);311	return 0;312}313