Commit c827ba4c authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Update defconfig.
  [SPARC64]: Add PCI MSI support on Niagara.
  [SPARC64] IRQ: Use irq_desc->chip_data instead of irq_desc->handler_data
  [SPARC64]: Add obppath sysfs attribute for SBUS and PCI devices.
  [PARTITION]: Add whole_disk attribute.
parents fdba0f2d 784020fb
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.20-rc2
# Thu Dec 28 15:09:49 2006
# Linux kernel version: 2.6.20
# Sat Feb 10 23:08:12 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
......@@ -151,7 +151,7 @@ CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_PCI_MULTITHREAD_PROBE is not set
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
CONFIG_SUN_OPENPROMFS=m
CONFIG_SPARC32_COMPAT=y
......@@ -182,7 +182,9 @@ CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_XFRM_MIGRATE=y
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
......@@ -300,6 +302,7 @@ CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
#
......@@ -393,6 +396,7 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT8213 is not set
# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
......@@ -402,6 +406,7 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_TC86C001 is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
......@@ -579,6 +584,7 @@ CONFIG_NET_PCI=y
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
#
# Ethernet (1000 Mbit)
......@@ -601,11 +607,13 @@ CONFIG_E1000_NAPI=y
CONFIG_TIGON3=m
CONFIG_BNX2=m
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
......@@ -627,8 +635,17 @@ CONFIG_BNX2=m
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
CONFIG_PPP=m
CONFIG_PPP_MULTILINK=y
CONFIG_PPP_FILTER=y
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
......@@ -1042,6 +1059,11 @@ CONFIG_SND_ALI5451=m
CONFIG_SND_SUN_CS4231=m
# CONFIG_SND_SUN_DBRI is not set
#
# SoC audio support
#
# CONFIG_SND_SOC is not set
#
# Open Sound System
#
......@@ -1052,6 +1074,7 @@ CONFIG_AC97_BUS=m
# HID Devices
#
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
# USB support
......@@ -1066,9 +1089,7 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
......@@ -1078,9 +1099,11 @@ CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=m
# CONFIG_USB_SL811_HCD is not set
......@@ -1132,6 +1155,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
# CONFIG_USB_GTCO is not set
#
# USB Imaging devices
......@@ -1473,8 +1497,10 @@ CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_GF128MUL=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
......@@ -1489,6 +1515,7 @@ CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_TEST=m
#
......
......@@ -22,6 +22,7 @@
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
#include <linux/msi.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
......@@ -87,7 +88,6 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
static unsigned int virt_to_real_irq_table[NR_IRQS];
static unsigned char virt_irq_cur = 1;
static unsigned char virt_irq_alloc(unsigned int real_irq)
{
......@@ -95,26 +95,32 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
BUILD_BUG_ON(NR_IRQS >= 256);
ent = virt_irq_cur;
for (ent = 1; ent < NR_IRQS; ent++) {
if (!virt_to_real_irq_table[ent])
break;
}
if (ent >= NR_IRQS) {
printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
return 0;
}
virt_irq_cur = ent + 1;
virt_to_real_irq_table[ent] = real_irq;
return ent;
}
#if 0 /* Currently unused. */
static unsigned char real_to_virt_irq(unsigned int real_irq)
static void virt_irq_free(unsigned int virt_irq)
{
struct ino_bucket *bucket = __bucket(real_irq);
unsigned int real_irq;
return bucket->virt_irq;
if (virt_irq >= NR_IRQS)
return;
real_irq = virt_to_real_irq_table[virt_irq];
virt_to_real_irq_table[virt_irq] = 0;
__bucket(real_irq)->virt_irq = 0;
}
#endif
static unsigned int virt_to_real_irq(unsigned char virt_irq)
{
......@@ -268,8 +274,7 @@ static int irq_choose_cpu(unsigned int virt_irq)
static void sun4u_irq_enable(unsigned int virt_irq)
{
irq_desc_t *desc = irq_desc + virt_irq;
struct irq_handler_data *data = desc->handler_data;
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data)) {
unsigned long cpuid, imap;
......@@ -286,8 +291,7 @@ static void sun4u_irq_enable(unsigned int virt_irq)
static void sun4u_irq_disable(unsigned int virt_irq)
{
irq_desc_t *desc = irq_desc + virt_irq;
struct irq_handler_data *data = desc->handler_data;
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data)) {
unsigned long imap = data->imap;
......@@ -300,8 +304,7 @@ static void sun4u_irq_disable(unsigned int virt_irq)
static void sun4u_irq_end(unsigned int virt_irq)
{
irq_desc_t *desc = irq_desc + virt_irq;
struct irq_handler_data *data = desc->handler_data;
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data))
upa_writel(ICLR_IDLE, data->iclr);
......@@ -344,6 +347,20 @@ static void sun4v_irq_disable(unsigned int virt_irq)
}
}
#ifdef CONFIG_PCI_MSI
static void sun4v_msi_enable(unsigned int virt_irq)
{
sun4v_irq_enable(virt_irq);
unmask_msi_irq(virt_irq);
}
static void sun4v_msi_disable(unsigned int virt_irq)
{
mask_msi_irq(virt_irq);
sun4v_irq_disable(virt_irq);
}
#endif
static void sun4v_irq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
......@@ -362,8 +379,7 @@ static void sun4v_irq_end(unsigned int virt_irq)
static void run_pre_handler(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
irq_desc_t *desc = irq_desc + virt_irq;
struct irq_handler_data *data = desc->handler_data;
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data->pre_handler)) {
data->pre_handler(__irq_ino(__irq(bucket)),
......@@ -402,30 +418,47 @@ static struct irq_chip sun4v_irq_ack = {
.end = sun4v_irq_end,
};
#ifdef CONFIG_PCI_MSI
static struct irq_chip sun4v_msi = {
.typename = "sun4v+msi",
.mask = mask_msi_irq,
.unmask = unmask_msi_irq,
.enable = sun4v_msi_enable,
.disable = sun4v_msi_disable,
.ack = run_pre_handler,
.end = sun4v_irq_end,
};
#endif
void irq_install_pre_handler(int virt_irq,
void (*func)(unsigned int, void *, void *),
void *arg1, void *arg2)
{
irq_desc_t *desc = irq_desc + virt_irq;
struct irq_handler_data *data = desc->handler_data;
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
struct irq_chip *chip;
data->pre_handler = func;
data->pre_handler_arg1 = arg1;
data->pre_handler_arg2 = arg2;
if (desc->chip == &sun4u_irq_ack ||
desc->chip == &sun4v_irq_ack)
chip = get_irq_chip(virt_irq);
if (chip == &sun4u_irq_ack ||
chip == &sun4v_irq_ack
#ifdef CONFIG_PCI_MSI
|| chip == &sun4v_msi
#endif
)
return;
desc->chip = (desc->chip == &sun4u_irq ?
&sun4u_irq_ack : &sun4v_irq_ack);
chip = (chip == &sun4u_irq ?
&sun4u_irq_ack : &sun4v_irq_ack);
set_irq_chip(virt_irq, chip);
}
unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
irq_desc_t *desc;
int ino;
BUG_ON(tlb_type == hypervisor);
......@@ -434,11 +467,11 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
bucket = &ivector_table[ino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
irq_desc[bucket->virt_irq].chip = &sun4u_irq;
set_irq_chip(bucket->virt_irq, &sun4u_irq);
}
desc = irq_desc + bucket->virt_irq;
if (unlikely(desc->handler_data))
data = get_irq_chip_data(bucket->virt_irq);
if (unlikely(data))
goto out;
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
......@@ -446,7 +479,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
desc->handler_data = data;
set_irq_chip_data(bucket->virt_irq, data);
data->imap = imap;
data->iclr = iclr;
......@@ -460,7 +493,6 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned long sysino;
irq_desc_t *desc;
BUG_ON(tlb_type != hypervisor);
......@@ -468,11 +500,11 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
bucket = &ivector_table[sysino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
irq_desc[bucket->virt_irq].chip = &sun4v_irq;
set_irq_chip(bucket->virt_irq, &sun4v_irq);
}
desc = irq_desc + bucket->virt_irq;
if (unlikely(desc->handler_data))
data = get_irq_chip_data(bucket->virt_irq);
if (unlikely(data))
goto out;
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
......@@ -480,7 +512,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
desc->handler_data = data;
set_irq_chip_data(bucket->virt_irq, data);
/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
......@@ -493,6 +525,56 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
return bucket->virt_irq;
}
#ifdef CONFIG_PCI_MSI
unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_start, unsigned int msi_end)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned long sysino;
unsigned int devino;
BUG_ON(tlb_type != hypervisor);
/* Find a free devino in the given range. */
for (devino = msi_start; devino < msi_end; devino++) {
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
if (!bucket->virt_irq)
break;
}
if (devino >= msi_end)
return 0;
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
*virt_irq_p = bucket->virt_irq;
set_irq_chip(bucket->virt_irq, &sun4v_msi);
data = get_irq_chip_data(bucket->virt_irq);
if (unlikely(data))
return devino;
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data)) {
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
set_irq_chip_data(bucket->virt_irq, data);
data->imap = ~0UL;
data->iclr = ~0UL;
return devino;
}
void sun4v_destroy_msi(unsigned int virt_irq)
{
virt_irq_free(virt_irq);
}
#endif
void ack_bad_irq(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
......
......@@ -13,6 +13,8 @@
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <asm/uaccess.h>
......@@ -646,4 +648,37 @@ int pci_domain_nr(struct pci_bus *pbus)
}
EXPORT_SYMBOL(pci_domain_nr);
#ifdef CONFIG_PCI_MSI
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
struct pci_controller_info *p = pbm->parent;
int virt_irq, err;
if (!pbm->msi_num || !p->setup_msi_irq)
return -EINVAL;
err = p->setup_msi_irq(&virt_irq, pdev, desc);
if (err < 0)
return err;
return virt_irq;
}
void arch_teardown_msi_irq(unsigned int virt_irq)
{
struct msi_desc *entry = get_irq_data(virt_irq);
struct pci_dev *pdev = entry->dev;
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
struct pci_controller_info *p = pbm->parent;
if (!pbm->msi_num || !p->setup_msi_irq)
return;
return p->teardown_msi_irq(virt_irq, pdev);
}
#endif /* !(CONFIG_PCI_MSI) */
#endif /* !(CONFIG_PCI) */
......@@ -7,6 +7,8 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <asm/pbm.h>
#include <asm/prom.h>
......@@ -129,6 +131,20 @@ static void __init fixup_obp_assignments(struct pci_dev *pdev,
}
}
static ssize_t
show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
{
struct pci_dev *pdev;
struct pcidev_cookie *sysdata;
pdev = to_pci_dev(dev);
sysdata = pdev->sysdata;
return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name);
}
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
/* Fill in the PCI device cookie sysdata for the given
* PCI device. This cookie is the means by which one
* can get to OBP and PCI controller specific information
......@@ -142,7 +158,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
struct pcidev_cookie *pcp;
struct device_node *dp;
struct property *prop;
int nregs, len;
int nregs, len, err;
dp = find_device_prom_node(pbm, pdev, bus_node,
&pregs, &nregs);
......@@ -215,6 +231,13 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
fixup_obp_assignments(pdev, pcp);
pdev->sysdata = pcp;
/* we don't really care if we can create this file or not,
* but we need to assign the result of the call or the world will fall
* under alien invasion and everybody will be frozen on a spaceship
* ready to be eaten on alpha centauri by some green and jelly humanoid.
*/
err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr);
}
void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
......
......@@ -10,6 +10,8 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/irq.h>
#include <linux/msi.h>
#include <asm/pbm.h>
#include <asm/iommu.h>
......@@ -1074,6 +1076,443 @@ static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
}
#ifdef CONFIG_PCI_MSI
struct pci_sun4v_msiq_entry {
u64 version_type;
#define MSIQ_VERSION_MASK 0xffffffff00000000UL
#define MSIQ_VERSION_SHIFT 32
#define MSIQ_TYPE_MASK 0x00000000000000ffUL
#define MSIQ_TYPE_SHIFT 0
#define MSIQ_TYPE_NONE 0x00
#define MSIQ_TYPE_MSG 0x01
#define MSIQ_TYPE_MSI32 0x02
#define MSIQ_TYPE_MSI64 0x03
#define MSIQ_TYPE_INTX 0x08
#define MSIQ_TYPE_NONE2 0xff
u64 intx_sysino;
u64 reserved1;
u64 stick;
u64 req_id; /* bus/device/func */
#define MSIQ_REQID_BUS_MASK 0xff00UL
#define MSIQ_REQID_BUS_SHIFT 8
#define MSIQ_REQID_DEVICE_MASK 0x00f8UL
#define MSIQ_REQID_DEVICE_SHIFT 3
#define MSIQ_REQID_FUNC_MASK 0x0007UL
#define MSIQ_REQID_FUNC_SHIFT 0
u64 msi_address;
/* The format of this value is message type dependant.
* For MSI bits 15:0 are the data from the MSI packet.
* For MSI-X bits 31:0 are the data from the MSI packet.
* For MSG, the message code and message routing code where:
* bits 39:32 is the bus/device/fn of the msg target-id
* bits 18:16 is the message routing code
* bits 7:0 is the message code
* For INTx the low order 2-bits are:
* 00 - INTA
* 01 - INTB
* 10 - INTC
* 11 - INTD
*/
u64 msi_data;
u64 reserved2;
};
/* For now this just runs as a pre-handler for the real interrupt handler.
* So we just walk through the queue and ACK all the entries, update the
* head pointer, and return.
*
* In the longer term it would be nice to do something more integrated
* wherein we can pass in some of this MSI info to the drivers. This
* would be most useful for PCIe fabric error messages, although we could
* invoke those directly from the loop here in order to pass the info around.
*/
static void pci_sun4v_msi_prehandler(unsigned int ino, void *data1, void *data2)
{
struct pci_pbm_info *pbm = data1;
struct pci_sun4v_msiq_entry *base, *ep;
unsigned long msiqid, orig_head, head, type, err;
msiqid = (unsigned long) data2;
head = 0xdeadbeef;
err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, &head);
if (unlikely(err))
goto hv_error_get;
if (unlikely(head >= (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry))))
goto bad_offset;
head /= sizeof(struct pci_sun4v_msiq_entry);
orig_head = head;
base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
(pbm->msiq_ent_count *
sizeof(struct pci_sun4v_msiq_entry))));
ep = &base[head];
while ((ep->version_type & MSIQ_TYPE_MASK) != 0) {
type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
if (unlikely(type != MSIQ_TYPE_MSI32 &&
type != MSIQ_TYPE_MSI64))
goto bad_type;
pci_sun4v_msi_setstate(pbm->devhandle,
ep->msi_data /* msi_num */,
HV_MSISTATE_IDLE);
/* Clear the entry. */
ep->version_type &= ~MSIQ_TYPE_MASK;
/* Go to next entry in ring. */
head++;
if (head >= pbm->msiq_ent_count)
head = 0;
ep = &base[head];
}
if (likely(head != orig_head)) {
/* ACK entries by updating head pointer. */
head *= sizeof(struct pci_sun4v_msiq_entry);
err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
if (unlikely(err))
goto hv_error_set;
}
return;
hv_error_set:
printk(KERN_EMERG "MSI: Hypervisor set head gives error %lu\n", err);
goto hv_error_cont;
hv_error_get:
printk(KERN_EMERG "MSI: Hypervisor get head gives error %lu\n", err);
hv_error_cont:
printk(KERN_EMERG "MSI: devhandle[%x] msiqid[%lx] head[%lu]\n",
pbm->devhandle, msiqid, head);
return;
bad_offset:
printk(KERN_EMERG "MSI: Hypervisor gives bad offset %lx max(%lx)\n",
head, pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry));
return;
bad_type:
printk(KERN_EMERG "MSI: Entry has bad type %lx\n", type);
return;
}
static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
{
unsigned long size, bits_per_ulong;
bits_per_ulong = sizeof(unsigned long) * 8;
size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
size /= 8;
BUG_ON(size % sizeof(unsigned long));
pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
if (!pbm->msi_bitmap)
return -ENOMEM;
return 0;
}
static void msi_bitmap_free(struct pci_pbm_info *pbm)
{
kfree(pbm->msi_bitmap);
pbm->msi_bitmap = NULL;
}
static int msi_queue_alloc(struct pci_pbm_info *pbm)
{
unsigned long q_size, alloc_size, pages, order;
int i;
q_size = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
alloc_size = (pbm->msiq_num * q_size);
order = get_order(alloc_size);
pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order);
if (pages == 0UL) {
printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n",
order);
return -ENOMEM;
}
memset((char *)pages, 0, PAGE_SIZE << order);
pbm->msi_queues = (void *) pages;
for (i = 0; i < pbm->msiq_num; i++) {
unsigned long err, base = __pa(pages + (i * q_size));
unsigned long ret1, ret2;
err = pci_sun4v_msiq_conf(pbm->devhandle,
pbm->msiq_first + i,
base, pbm->msiq_ent_count);
if (err) {
printk(KERN_ERR "MSI: msiq register fails (err=%lu)\n",
err);
goto h_error;
}
err = pci_sun4v_msiq_info(pbm->devhandle,
pbm->msiq_first + i,
&ret1, &ret2);
if (err) {
printk(KERN_ERR "MSI: Cannot read msiq (err=%lu)\n",
err);
goto h_error;
}
if (ret1 != base || ret2 != pbm->msiq_ent_count) {
printk(KERN_ERR "MSI: Bogus qconf "
"expected[%lx:%x] got[%lx:%lx]\n",
base, pbm->msiq_ent_count,
ret1, ret2);
goto h_error;
}
}
return 0;
h_error:
free_pages(pages, order);
return -EINVAL;
}
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
u32 *val;
int len;
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_num = *val;
if (pbm->msiq_num) {
struct msiq_prop {
u32 first_msiq;
u32 num_msiq;
u32 first_devino;
} *mqp;
struct msi_range_prop {
u32 first_msi;
u32 num_msi;
} *mrng;
struct addr_range_prop {
u32 msi32_high;
u32 msi32_low;
u32 msi32_len;
u32 msi64_high;
u32 msi64_low;
u32 msi64_len;
} *arng;
val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_ent_count = *val;
mqp = of_get_property(pbm->prom_node,
"msi-eq-to-devino", &len);
if (!mqp || len != sizeof(struct msiq_prop))
goto no_msi;
pbm->msiq_first = mqp->first_msiq;
pbm->msiq_first_devino = mqp->first_devino;
val = of_get_property(pbm->prom_node, "#msi", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_num = *val;
mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
if (!mrng || len != sizeof(struct msi_range_prop))
goto no_msi;
pbm->msi_first = mrng->first_msi;
val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_data_mask = *val;
val = of_get_property(pbm->prom_node, "msix-data-width", &len);
if (!val || len != 4)
goto no_msi;
pbm->msix_data_width = *val;
arng = of_get_property(pbm->prom_node, "msi-address-ranges",
&len);
if (!arng || len != sizeof(struct addr_range_prop))
goto no_msi;
pbm->msi32_start = ((u64)arng->msi32_high << 32) |
(u64) arng->msi32_low;
pbm->msi64_start = ((u64)arng->msi64_high << 32) |
(u64) arng->msi64_low;
pbm->msi32_len = arng->msi32_len;
pbm->msi64_len = arng->msi64_len;
if (msi_bitmap_alloc(pbm))
goto no_msi;
if (msi_queue_alloc(pbm)) {
msi_bitmap_free(pbm);
goto no_msi;
}
printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
"devino[0x%x]\n",
pbm->name,
pbm->msiq_first, pbm->msiq_num,
pbm->msiq_ent_count,
pbm->msiq_first_devino);
printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
"width[%u]\n",
pbm->name,
pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
pbm->msix_data_width);
printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
"addr64[0x%lx:0x%x]\n",
pbm->name,
pbm->msi32_start, pbm->msi32_len,
pbm->msi64_start, pbm->msi64_len);
printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
pbm->name,
pbm->msi_queues);
}
return;
no_msi:
pbm->msiq_num = 0;
printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
}
static int alloc_msi(struct pci_pbm_info *pbm)
{
int i;
for (i = 0; i < pbm->msi_num; i++) {
if (!test_and_set_bit(i, pbm->msi_bitmap))
return i + pbm->msi_first;
}
return -ENOENT;
}
static void free_msi(struct pci_pbm_info *pbm, int msi_num)
{
msi_num -= pbm->msi_first;
clear_bit(msi_num, pbm->msi_bitmap);
}
static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
struct pci_dev *pdev,
struct msi_desc *entry)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
unsigned long devino, msiqid;
struct msi_msg msg;
int msi_num, err;
*virt_irq_p = 0;
msi_num = alloc_msi(pbm);
if (msi_num < 0)
return msi_num;
devino = sun4v_build_msi(pbm->devhandle, virt_irq_p,
pbm->msiq_first_devino,
(pbm->msiq_first_devino +
pbm->msiq_num));
err = -ENOMEM;
if (!devino)
goto out_err;
set_irq_msi(*virt_irq_p, entry);
msiqid = ((devino - pbm->msiq_first_devino) +
pbm->msiq_first);
err = -EINVAL;
if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
if (err)
goto out_err;
if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
goto out_err;
if (pci_sun4v_msi_setmsiq(pbm->devhandle,
msi_num, msiqid,
(entry->msi_attrib.is_64 ?
HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
goto out_err;
if (pci_sun4v_msi_setstate(pbm->devhandle, msi_num, HV_MSISTATE_IDLE))
goto out_err;
if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
goto out_err;
pcp->msi_num = msi_num;
if (entry->msi_attrib.is_64) {
msg.address_hi = pbm->msi64_start >> 32;
msg.address_lo = pbm->msi64_start & 0xffffffff;
} else {
msg.address_hi = 0;
msg.address_lo = pbm->msi32_start;
}
msg.data = msi_num;
write_msi_msg(*virt_irq_p, &msg);
irq_install_pre_handler(*virt_irq_p,
pci_sun4v_msi_prehandler,
pbm, (void *) msiqid);
return 0;
out_err:
free_msi(pbm, msi_num);
sun4v_destroy_msi(*virt_irq_p);
*virt_irq_p = 0;
return err;
}
static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
struct pci_dev *pdev)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
unsigned long msiqid, err;
unsigned int msi_num;
msi_num = pcp->msi_num;
err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
if (err) {
printk(KERN_ERR "%s: getmsiq gives error %lu\n",
pbm->name, err);
return;
}
pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_INVALID);
pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_INVALID);
free_msi(pbm, msi_num);
/* The sun4v_destroy_msi() will liberate the devino and thus the MSIQ
* allocation.
*/
sun4v_destroy_msi(virt_irq);
}
#else /* CONFIG_PCI_MSI */
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
}
#endif /* !(CONFIG_PCI_MSI) */
static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
......@@ -1119,6 +1558,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
pci_sun4v_get_bus_range(pbm);
pci_sun4v_iommu_init(pbm);
pci_sun4v_msi_init(pbm);
pdev_htab_populate(pbm);
}
......@@ -1187,6 +1627,10 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
p->scan_bus = pci_sun4v_scan_bus;
p->base_address_update = pci_sun4v_base_address_update;
p->resource_adjust = pci_sun4v_resource_adjust;
#ifdef CONFIG_PCI_MSI
p->setup_msi_irq = pci_sun4v_setup_msi_irq;
p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
#endif
p->pci_ops = &pci_sun4v_ops;
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
......
......@@ -28,4 +28,65 @@ extern int pci_sun4v_config_put(unsigned long devhandle,
unsigned long size,
unsigned long data);
extern unsigned long pci_sun4v_msiq_conf(unsigned long devhandle,
unsigned long msiqid,
unsigned long msiq_paddr,
unsigned long num_entries);
extern unsigned long pci_sun4v_msiq_info(unsigned long devhandle,
unsigned long msiqid,
unsigned long *msiq_paddr,
unsigned long *num_entries);
extern unsigned long pci_sun4v_msiq_getvalid(unsigned long devhandle,
unsigned long msiqid,
unsigned long *valid);
extern unsigned long pci_sun4v_msiq_setvalid(unsigned long devhandle,
unsigned long msiqid,
unsigned long valid);
extern unsigned long pci_sun4v_msiq_getstate(unsigned long devhandle,
unsigned long msiqid,
unsigned long *state);
extern unsigned long pci_sun4v_msiq_setstate(unsigned long devhandle,
unsigned long msiqid,
unsigned long state);
extern unsigned long pci_sun4v_msiq_gethead(unsigned long devhandle,
unsigned long msiqid,
unsigned long *head);
extern unsigned long pci_sun4v_msiq_sethead(unsigned long devhandle,
unsigned long msiqid,
unsigned long head);
extern unsigned long pci_sun4v_msiq_gettail(unsigned long devhandle,
unsigned long msiqid,
unsigned long *head);
extern unsigned long pci_sun4v_msi_getvalid(unsigned long devhandle,
unsigned long msinum,
unsigned long *valid);
extern unsigned long pci_sun4v_msi_setvalid(unsigned long devhandle,
unsigned long msinum,
unsigned long valid);
extern unsigned long pci_sun4v_msi_getmsiq(unsigned long devhandle,
unsigned long msinum,
unsigned long *msiq);
extern unsigned long pci_sun4v_msi_setmsiq(unsigned long devhandle,
unsigned long msinum,
unsigned long msiq,
unsigned long msitype);
extern unsigned long pci_sun4v_msi_getstate(unsigned long devhandle,
unsigned long msinum,
unsigned long *state);
extern unsigned long pci_sun4v_msi_setstate(unsigned long devhandle,
unsigned long msinum,
unsigned long state);
extern unsigned long pci_sun4v_msg_getmsiq(unsigned long devhandle,
unsigned long msinum,
unsigned long *msiq);
extern unsigned long pci_sun4v_msg_setmsiq(unsigned long devhandle,
unsigned long msinum,
unsigned long msiq);
extern unsigned long pci_sun4v_msg_getvalid(unsigned long devhandle,
unsigned long msinum,
unsigned long *valid);
extern unsigned long pci_sun4v_msg_setvalid(unsigned long devhandle,
unsigned long msinum,
unsigned long valid);
#endif /* !(_PCI_SUN4V_H) */
......@@ -93,3 +93,269 @@ pci_sun4v_config_put:
mov -1, %o1
1: retl
mov %o1, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: msiq phys address
* %o3: num entries
*
* returns %o0: status
*
* status will be zero if the operation completed
* successfully, else -1 if not
*/
.globl pci_sun4v_msiq_conf
pci_sun4v_msiq_conf:
mov HV_FAST_PCI_MSIQ_CONF, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: &msiq_phys_addr
* %o3: &msiq_num_entries
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_info
pci_sun4v_msiq_info:
mov %o2, %o4
mov HV_FAST_PCI_MSIQ_INFO, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
stx %o2, [%o3]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: &valid
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_getvalid
pci_sun4v_msiq_getvalid:
mov HV_FAST_PCI_MSIQ_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: valid
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_setvalid
pci_sun4v_msiq_setvalid:
mov HV_FAST_PCI_MSIQ_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: &state
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_getstate
pci_sun4v_msiq_getstate:
mov HV_FAST_PCI_MSIQ_GETSTATE, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: state
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_setstate
pci_sun4v_msiq_setstate:
mov HV_FAST_PCI_MSIQ_SETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: &head
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_gethead
pci_sun4v_msiq_gethead:
mov HV_FAST_PCI_MSIQ_GETHEAD, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: head
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_sethead
pci_sun4v_msiq_sethead:
mov HV_FAST_PCI_MSIQ_SETHEAD, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msiqid
* %o2: &tail
*
* returns %o0: status
*/
.globl pci_sun4v_msiq_gettail
pci_sun4v_msiq_gettail:
mov HV_FAST_PCI_MSIQ_GETTAIL, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: &valid
*
* returns %o0: status
*/
.globl pci_sun4v_msi_getvalid
pci_sun4v_msi_getvalid:
mov HV_FAST_PCI_MSI_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: valid
*
* returns %o0: status
*/
.globl pci_sun4v_msi_setvalid
pci_sun4v_msi_setvalid:
mov HV_FAST_PCI_MSI_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: &msiq
*
* returns %o0: status
*/
.globl pci_sun4v_msi_getmsiq
pci_sun4v_msi_getmsiq:
mov HV_FAST_PCI_MSI_GETMSIQ, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: msitype
* %o3: msiq
*
* returns %o0: status
*/
.globl pci_sun4v_msi_setmsiq
pci_sun4v_msi_setmsiq:
mov HV_FAST_PCI_MSI_SETMSIQ, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: &state
*
* returns %o0: status
*/
.globl pci_sun4v_msi_getstate
pci_sun4v_msi_getstate:
mov HV_FAST_PCI_MSI_GETSTATE, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: state
*
* returns %o0: status
*/
.globl pci_sun4v_msi_setstate
pci_sun4v_msi_setstate:
mov HV_FAST_PCI_MSI_SETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: &msiq
*
* returns %o0: status
*/
.globl pci_sun4v_msg_getmsiq
pci_sun4v_msg_getmsiq:
mov HV_FAST_PCI_MSG_GETMSIQ, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: msiq
*
* returns %o0: status
*/
.globl pci_sun4v_msg_setmsiq
pci_sun4v_msg_setmsiq:
mov HV_FAST_PCI_MSG_SETMSIQ, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: &valid
*
* returns %o0: status
*/
.globl pci_sun4v_msg_getvalid
pci_sun4v_msg_getvalid:
mov HV_FAST_PCI_MSG_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: msinum
* %o2: valid
*
* returns %o0: status
*/
.globl pci_sun4v_msg_setvalid
pci_sun4v_msg_setvalid:
mov HV_FAST_PCI_MSG_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
......@@ -61,7 +61,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
}
}
/* all seems OK */
add_partition(disk, part, start, length);
add_partition(disk, part, start, length, ADDPART_FLAG_NONE);
mutex_unlock(&bdev->bd_mutex);
return 0;
case BLKPG_DEL_PARTITION:
......
......@@ -4,7 +4,7 @@
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64
help
This allows device drivers to enable MSI (Message Signaled
Interrupts). Message Signaled Interrupts enable a device to
......
......@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <asm/system.h>
#include <asm/sbus.h>
......@@ -17,13 +18,25 @@
#include <asm/bpp.h>
#include <asm/irq.h>
static ssize_t
show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
{
struct sbus_dev *sbus;
sbus = to_sbus_device(dev);
return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
}
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
unsigned long base;
void *pval;
int len;
int len, err;
sdev->prom_node = dp->node;
strcpy(sdev->prom_name, dp->name);
......@@ -66,6 +79,9 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
if (of_device_register(&sdev->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
dp->path_component_name);
/* WE HAVE BEEN INVADED BY ALIENS! */
err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
}
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
......
......@@ -365,7 +365,7 @@ void delete_partition(struct gendisk *disk, int part)
kobject_put(&p->kobj);
}
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
{
struct hd_struct *p;
......@@ -390,6 +390,15 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
if (!disk->part_uevent_suppress)
kobject_uevent(&p->kobj, KOBJ_ADD);
sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem");
if (flags & ADDPART_FLAG_WHOLEDISK) {
static struct attribute addpartattr = {
.name = "whole_disk",
.mode = S_IRUSR | S_IRGRP | S_IROTH,
.owner = THIS_MODULE,
};
sysfs_create_file(&p->kobj, &addpartattr);
}
partition_sysfs_add_subdir(p);
disk->part[part-1] = p;
}
......@@ -543,9 +552,9 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
printk(" %s: p%d exceeds device capacity\n",
disk->disk_name, p);
}
add_partition(disk, p, from, size);
add_partition(disk, p, from, size, state->parts[p].flags);
#ifdef CONFIG_BLK_DEV_MD
if (state->parts[p].flags)
if (state->parts[p].flags & ADDPART_FLAG_RAID)
md_autodetect_dev(bdev->bd_dev+p);
#endif
}
......
......@@ -165,7 +165,7 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev,
put_partition(state, state->next, next, size);
if (SYS_IND(p) == LINUX_RAID_PARTITION)
state->parts[state->next].flags = 1;
state->parts[state->next].flags = ADDPART_FLAG_RAID;
loopct = 0;
if (++state->next == state->limit)
goto done;
......
......@@ -72,7 +72,7 @@ int sgi_partition(struct parsed_partitions *state, struct block_device *bdev)
if (blocks) {
put_partition(state, slot, start, blocks);
if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
state->parts[slot].flags = 1;
state->parts[slot].flags = ADDPART_FLAG_RAID;
}
slot++;
}
......
......@@ -80,8 +80,11 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev)
num_sectors = be32_to_cpu(p->num_sectors);
if (num_sectors) {
put_partition(state, slot, st_sector, num_sectors);
state->parts[slot].flags = 0;
if (label->infos[i].id == LINUX_RAID_PARTITION)
state->parts[slot].flags = 1;
state->parts[slot].flags |= ADDPART_FLAG_RAID;
if (label->infos[i].id == SUN_WHOLE_DISK)
state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK;
}
slot++;
}
......
......@@ -46,6 +46,10 @@ extern void irq_install_pre_handler(int virt_irq,
#define irq_canonicalize(irq) (irq)
extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap);
extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino);
extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_devino_start,
unsigned int msi_devino_end);
extern void sun4v_destroy_msi(unsigned int virt_irq);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
static __inline__ void set_softint(unsigned long bits)
......
......@@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/msi.h>
#include <asm/io.h>
#include <asm/page.h>
......@@ -177,6 +178,24 @@ struct pci_pbm_info {
int is_66mhz_capable;
int all_devs_66mhz;
#ifdef CONFIG_PCI_MSI
/* MSI info. */
u32 msiq_num;
u32 msiq_ent_count;
u32 msiq_first;
u32 msiq_first_devino;
u32 msi_num;
u32 msi_first;
u32 msi_data_mask;
u32 msix_data_width;
u64 msi32_start;
u64 msi64_start;
u32 msi32_len;
u32 msi64_len;
void *msi_queues;
unsigned long *msi_bitmap;
#endif /* !(CONFIG_PCI_MSI) */
/* This PBM's streaming buffer. */
struct pci_strbuf stc;
......@@ -213,6 +232,12 @@ struct pci_controller_info {
void (*base_address_update)(struct pci_dev *, int);
void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *);
#ifdef CONFIG_PCI_MSI
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
struct msi_desc *entry);
void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
#endif
/* Now things for the actual PCI bus probes. */
struct pci_ops *pci_ops;
unsigned int pci_first_busno;
......@@ -231,6 +256,9 @@ struct pcidev_cookie {
int num_prom_regs;
struct linux_prom_pci_registers prom_assignments[PROMREG_MAX];
int num_prom_assignments;
#ifdef CONFIG_PCI_MSI
unsigned int msi_num;
#endif
};
/* Currently these are the same across all PCI controllers
......
......@@ -20,6 +20,8 @@ enum {
LINUX_EXTENDED_PARTITION = 0x85,
WIN98_EXTENDED_PARTITION = 0x0f,
SUN_WHOLE_DISK = DOS_EXTENDED_PARTITION,
LINUX_SWAP_PARTITION = 0x82,
LINUX_DATA_PARTITION = 0x83,
LINUX_LVM_PARTITION = 0x8e,
......@@ -402,10 +404,14 @@ struct unixware_disklabel {
#ifdef __KERNEL__
#define ADDPART_FLAG_NONE 0
#define ADDPART_FLAG_RAID 1
#define ADDPART_FLAG_WHOLEDISK 2
char *disk_name (struct gendisk *hd, int part, char *buf);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
extern void add_partition(struct gendisk *, int, sector_t, sector_t);
extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
extern void delete_partition(struct gendisk *, int);
extern struct gendisk *alloc_disk_node(int minors, int node_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment