Message ID | 20231212053723.443772-3-Raju.Rangoju@amd.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | amd-xgbe: add support for AMD Crater | expand |
On 12/11/23 23:37, Raju Rangoju wrote: > Add the necessary support to enable Crater ethernet device. Since the > BAR1 address cannot be used to access the XPCS registers on Crater, use > the pci_{read/write}_config_dword calls. Also, include the new pci device > id 0x1641 to register Crater device with PCIe. > > Co-developed-by: Sudheesh Mavila <sudheesh.mavila@amd.com> > Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> > Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com> > --- > drivers/net/ethernet/amd/xgbe/xgbe-common.h | 5 ++ > drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 93 +++++++++++++++++++++ > drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 35 +++++++- > drivers/net/ethernet/amd/xgbe/xgbe.h | 6 ++ > 4 files changed, 137 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h > index 3b70f6737633..e1f70f0528ef 100644 > --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h > +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h > @@ -900,6 +900,11 @@ > #define PCS_V2_RV_WINDOW_SELECT 0x1064 > #define PCS_V2_YC_WINDOW_DEF 0x18060 > #define PCS_V2_YC_WINDOW_SELECT 0x18064 > +#define PCS_V2_RN_WINDOW_DEF 0xF8078 > +#define PCS_V2_RN_WINDOW_SELECT 0xF807c Should this be PCS_V3_ (here and below) ?? > + > +#define PCS_RN_SMN_BASE_ADDR 0x11E00000 > +#define PCS_RN_PORT_ADDR_SIZE 0x100000 All hex characters should be consistent and in lower case. > > /* PCS register entry bit positions and sizes */ > #define PCS_V2_WINDOW_DEF_OFFSET_INDEX 6 > diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c > index 6cd003c24a64..a9eb2ffa9f73 100644 > --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c > +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c > @@ -120,6 +120,7 @@ > #include <linux/bitrev.h> > #include <linux/crc32.h> > #include <linux/crc32poly.h> > +#include <linux/pci.h> > > #include "xgbe.h" > #include "xgbe-common.h" > @@ -1165,6 +1166,92 @@ static unsigned int get_index_offset(struct xgbe_prv_data *pdata, unsigned int m > return pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); > } > > +static int xgbe_read_mmd_regs_v3(struct xgbe_prv_data *pdata, int prtad, > + int mmd_reg) > +{ > + unsigned int mmd_address, index, offset; > + struct pci_dev *rdev; > + unsigned long flags; > + int mmd_data; > + > + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); > + if (!rdev) > + return 0; > + > + mmd_address = get_mmd_address(pdata, mmd_reg); > + > + /* The PCS registers are accessed using mmio. The underlying > + * management interface uses indirect addressing to access the MMD > + * register sets. This requires accessing of the PCS register in two > + * phases, an address phase and a data phase. > + * > + * The mmio interface is based on 16-bit offsets and values. All > + * register offsets must therefore be adjusted by left shifting the > + * offset 1 bit and reading 16 bits of data. > + */ > + offset = get_index_offset(pdata, mmd_address, &index); > + > + spin_lock_irqsave(&pdata->xpcs_lock, flags); > + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); > + pci_write_config_dword(rdev, 0x64, index); > + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); > + pci_read_config_dword(rdev, 0x64, &mmd_data); > + mmd_data = (offset % 4) ? FIELD_GET(XGBE_GEN_HI_MASK, mmd_data) : > + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); > + pci_dev_put(rdev); > + > + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); > + > + return mmd_data; > +} > + > +static void xgbe_write_mmd_regs_v3(struct xgbe_prv_data *pdata, int prtad, > + int mmd_reg, int mmd_data) > +{ > + unsigned int mmd_address, index, offset, ctr_mmd_data; > + struct pci_dev *rdev; > + unsigned long flags; > + > + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); > + if (!rdev) > + return; > + > + mmd_address = get_mmd_address(pdata, mmd_reg); > + > + /* The PCS registers are accessed using mmio. The underlying > + * management interface uses indirect addressing to access the MMD > + * register sets. This requires accessing of the PCS register in two > + * phases, an address phase and a data phase. > + * > + * The mmio interface is based on 16-bit offsets and values. All > + * register offsets must therefore be adjusted by left shifting the > + * offset 1 bit and writing 16 bits of data. > + */ > + offset = get_index_offset(pdata, mmd_address, &index); > + > + spin_lock_irqsave(&pdata->xpcs_lock, flags); > + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); > + pci_write_config_dword(rdev, 0x64, index); > + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); > + pci_read_config_dword(rdev, 0x64, &ctr_mmd_data); > + if (offset % 4) { > + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, mmd_data) | > + FIELD_GET(XGBE_GEN_LO_MASK, ctr_mmd_data); > + } else { > + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, > + FIELD_GET(XGBE_GEN_HI_MASK, ctr_mmd_data)) | > + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); > + } Braces aren't necessary. Also, just curious, what is the "ctr" prefix meant to imply here? > + > + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); > + pci_write_config_dword(rdev, 0x64, index); > + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + offset)); > + pci_write_config_dword(rdev, 0x64, ctr_mmd_data); > + pci_dev_put(rdev); > + > + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); > +} > + > static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad, > int mmd_reg) > { > @@ -1274,6 +1361,9 @@ static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, > case XGBE_XPCS_ACCESS_V1: > return xgbe_read_mmd_regs_v1(pdata, prtad, mmd_reg); > > + case XGBE_XPCS_ACCESS_V3: > + return xgbe_read_mmd_regs_v3(pdata, prtad, mmd_reg); > + > case XGBE_XPCS_ACCESS_V2: > default: > return xgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg); > @@ -1287,6 +1377,9 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, > case XGBE_XPCS_ACCESS_V1: > return xgbe_write_mmd_regs_v1(pdata, prtad, mmd_reg, mmd_data); > > + case XGBE_XPCS_ACCESS_V3: > + return xgbe_write_mmd_regs_v3(pdata, prtad, mmd_reg, mmd_data); > + > case XGBE_XPCS_ACCESS_V2: > default: > return xgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data); > diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c > index 8b0c1e450b7e..db3e8aac3339 100644 > --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c > +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c > @@ -295,15 +295,28 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) > /* Yellow Carp devices do not need rrc */ > pdata->vdata->enable_rrc = 0; > break; > + case 0x1630: What PCI ID is this, it doesn't match the 0x1641 added below? Thanks, Tom > + pdata->xpcs_window_def_reg = PCS_V2_RN_WINDOW_DEF; > + pdata->xpcs_window_sel_reg = PCS_V2_RN_WINDOW_SELECT; > + break; > default: > pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF; > pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT; > break; > } > - pci_dev_put(rdev); > > /* Configure the PCS indirect addressing support */ > - reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); > + if (pdata->vdata->xpcs_access == XGBE_XPCS_ACCESS_V3) { > + reg = XP_IOREAD(pdata, XP_PROP_0); > + pdata->xphy_base = PCS_RN_SMN_BASE_ADDR + > + (PCS_RN_PORT_ADDR_SIZE * XP_GET_BITS(reg, XP_PROP_0, PORT_ID)); > + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + (pdata->xpcs_window_def_reg)); > + pci_read_config_dword(rdev, 0x64, ®); > + } else { > + reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); > + } > + pci_dev_put(rdev); > + > pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET); > pdata->xpcs_window <<= 6; > pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE); > @@ -481,6 +494,22 @@ static int __maybe_unused xgbe_pci_resume(struct device *dev) > return ret; > } > > +static struct xgbe_version_data xgbe_v3 = { > + .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, > + .xpcs_access = XGBE_XPCS_ACCESS_V3, > + .mmc_64bit = 1, > + .tx_max_fifo_size = 65536, > + .rx_max_fifo_size = 65536, > + .tx_tstamp_workaround = 1, > + .ecc_support = 1, > + .i2c_support = 1, > + .irq_reissue_support = 1, > + .tx_desc_prefetch = 5, > + .rx_desc_prefetch = 5, > + .an_cdr_workaround = 0, > + .enable_rrc = 0, > +}; > + > static struct xgbe_version_data xgbe_v2a = { > .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, > .xpcs_access = XGBE_XPCS_ACCESS_V2, > @@ -518,6 +547,8 @@ static const struct pci_device_id xgbe_pci_table[] = { > .driver_data = (kernel_ulong_t)&xgbe_v2a }, > { PCI_VDEVICE(AMD, 0x1459), > .driver_data = (kernel_ulong_t)&xgbe_v2b }, > + { PCI_VDEVICE(AMD, 0x1641), > + .driver_data = (kernel_ulong_t)&xgbe_v3 }, > /* Last entry must be zero */ > { 0, } > }; > diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h > index ad136ed493ed..dbb1faaf6185 100644 > --- a/drivers/net/ethernet/amd/xgbe/xgbe.h > +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h > @@ -347,6 +347,10 @@ > (_src)->link_modes._sname, \ > __ETHTOOL_LINK_MODE_MASK_NBITS) > > +/* Generic low and high masks */ > +#define XGBE_GEN_HI_MASK GENMASK(31, 16) > +#define XGBE_GEN_LO_MASK GENMASK(15, 0) > + > struct xgbe_prv_data; > > struct xgbe_packet_data { > @@ -565,6 +569,7 @@ enum xgbe_speed { > enum xgbe_xpcs_access { > XGBE_XPCS_ACCESS_V1 = 0, > XGBE_XPCS_ACCESS_V2, > + XGBE_XPCS_ACCESS_V3, > }; > > enum xgbe_an_mode { > @@ -1056,6 +1061,7 @@ struct xgbe_prv_data { > struct device *dev; > struct platform_device *phy_platdev; > struct device *phy_dev; > + unsigned int xphy_base; > > /* Version related data */ > struct xgbe_version_data *vdata;
On 12/12/2023 9:02 PM, Tom Lendacky wrote: > On 12/11/23 23:37, Raju Rangoju wrote: >> Add the necessary support to enable Crater ethernet device. Since the >> BAR1 address cannot be used to access the XPCS registers on Crater, use >> the pci_{read/write}_config_dword calls. Also, include the new pci device >> id 0x1641 to register Crater device with PCIe. >> >> Co-developed-by: Sudheesh Mavila <sudheesh.mavila@amd.com> >> Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> >> Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com> >> --- >> drivers/net/ethernet/amd/xgbe/xgbe-common.h | 5 ++ >> drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 93 +++++++++++++++++++++ >> drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 35 +++++++- >> drivers/net/ethernet/amd/xgbe/xgbe.h | 6 ++ >> 4 files changed, 137 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h >> b/drivers/net/ethernet/amd/xgbe/xgbe-common.h >> index 3b70f6737633..e1f70f0528ef 100644 >> --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h >> +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h >> @@ -900,6 +900,11 @@ >> #define PCS_V2_RV_WINDOW_SELECT 0x1064 >> #define PCS_V2_YC_WINDOW_DEF 0x18060 >> #define PCS_V2_YC_WINDOW_SELECT 0x18064 >> +#define PCS_V2_RN_WINDOW_DEF 0xF8078 >> +#define PCS_V2_RN_WINDOW_SELECT 0xF807c > > Should this be PCS_V3_ (here and below) ?? Yes, it should be PCS_V3. I'll take care of it in next version. > >> + >> +#define PCS_RN_SMN_BASE_ADDR 0x11E00000 >> +#define PCS_RN_PORT_ADDR_SIZE 0x100000 > > All hex characters should be consistent and in lower case. Sure > >> /* PCS register entry bit positions and sizes */ >> #define PCS_V2_WINDOW_DEF_OFFSET_INDEX 6 >> diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c >> b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c >> index 6cd003c24a64..a9eb2ffa9f73 100644 >> --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c >> +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c >> @@ -120,6 +120,7 @@ >> #include <linux/bitrev.h> >> #include <linux/crc32.h> >> #include <linux/crc32poly.h> >> +#include <linux/pci.h> >> #include "xgbe.h" >> #include "xgbe-common.h" >> @@ -1165,6 +1166,92 @@ static unsigned int get_index_offset(struct >> xgbe_prv_data *pdata, unsigned int m >> return pdata->xpcs_window + (mmd_address & >> pdata->xpcs_window_mask); >> } >> +static int xgbe_read_mmd_regs_v3(struct xgbe_prv_data *pdata, int prtad, >> + int mmd_reg) >> +{ >> + unsigned int mmd_address, index, offset; >> + struct pci_dev *rdev; >> + unsigned long flags; >> + int mmd_data; >> + >> + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); >> + if (!rdev) >> + return 0; >> + >> + mmd_address = get_mmd_address(pdata, mmd_reg); >> + >> + /* The PCS registers are accessed using mmio. The underlying >> + * management interface uses indirect addressing to access the MMD >> + * register sets. This requires accessing of the PCS register in two >> + * phases, an address phase and a data phase. >> + * >> + * The mmio interface is based on 16-bit offsets and values. All >> + * register offsets must therefore be adjusted by left shifting the >> + * offset 1 bit and reading 16 bits of data. >> + */ >> + offset = get_index_offset(pdata, mmd_address, &index); >> + >> + spin_lock_irqsave(&pdata->xpcs_lock, flags); >> + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + >> pdata->xpcs_window_sel_reg)); >> + pci_write_config_dword(rdev, 0x64, index); >> + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); >> + pci_read_config_dword(rdev, 0x64, &mmd_data); >> + mmd_data = (offset % 4) ? FIELD_GET(XGBE_GEN_HI_MASK, mmd_data) : >> + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); >> + pci_dev_put(rdev); >> + >> + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); >> + >> + return mmd_data; >> +} >> + >> +static void xgbe_write_mmd_regs_v3(struct xgbe_prv_data *pdata, int >> prtad, >> + int mmd_reg, int mmd_data) >> +{ >> + unsigned int mmd_address, index, offset, ctr_mmd_data; >> + struct pci_dev *rdev; >> + unsigned long flags; >> + >> + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); >> + if (!rdev) >> + return; >> + >> + mmd_address = get_mmd_address(pdata, mmd_reg); >> + >> + /* The PCS registers are accessed using mmio. The underlying >> + * management interface uses indirect addressing to access the MMD >> + * register sets. This requires accessing of the PCS register in two >> + * phases, an address phase and a data phase. >> + * >> + * The mmio interface is based on 16-bit offsets and values. All >> + * register offsets must therefore be adjusted by left shifting the >> + * offset 1 bit and writing 16 bits of data. >> + */ >> + offset = get_index_offset(pdata, mmd_address, &index); >> + >> + spin_lock_irqsave(&pdata->xpcs_lock, flags); >> + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + >> pdata->xpcs_window_sel_reg)); >> + pci_write_config_dword(rdev, 0x64, index); >> + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); >> + pci_read_config_dword(rdev, 0x64, &ctr_mmd_data); >> + if (offset % 4) { >> + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, mmd_data) | >> + FIELD_GET(XGBE_GEN_LO_MASK, ctr_mmd_data); >> + } else { >> + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, >> + FIELD_GET(XGBE_GEN_HI_MASK, ctr_mmd_data)) | >> + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); >> + } > > Braces aren't necessary. > > Also, just curious, what is the "ctr" prefix meant to imply here? ctr = crater. Will use the full name instead to avoid confusion. > > >> + >> + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + >> pdata->xpcs_window_sel_reg)); >> + pci_write_config_dword(rdev, 0x64, index); >> + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + offset)); >> + pci_write_config_dword(rdev, 0x64, ctr_mmd_data); >> + pci_dev_put(rdev); >> + >> + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); >> +} >> + >> static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int >> prtad, >> int mmd_reg) >> { >> @@ -1274,6 +1361,9 @@ static int xgbe_read_mmd_regs(struct >> xgbe_prv_data *pdata, int prtad, >> case XGBE_XPCS_ACCESS_V1: >> return xgbe_read_mmd_regs_v1(pdata, prtad, mmd_reg); >> + case XGBE_XPCS_ACCESS_V3: >> + return xgbe_read_mmd_regs_v3(pdata, prtad, mmd_reg); >> + >> case XGBE_XPCS_ACCESS_V2: >> default: >> return xgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg); >> @@ -1287,6 +1377,9 @@ static void xgbe_write_mmd_regs(struct >> xgbe_prv_data *pdata, int prtad, >> case XGBE_XPCS_ACCESS_V1: >> return xgbe_write_mmd_regs_v1(pdata, prtad, mmd_reg, mmd_data); >> + case XGBE_XPCS_ACCESS_V3: >> + return xgbe_write_mmd_regs_v3(pdata, prtad, mmd_reg, mmd_data); >> + >> case XGBE_XPCS_ACCESS_V2: >> default: >> return xgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data); >> diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c >> b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c >> index 8b0c1e450b7e..db3e8aac3339 100644 >> --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c >> +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c >> @@ -295,15 +295,28 @@ static int xgbe_pci_probe(struct pci_dev *pdev, >> const struct pci_device_id *id) >> /* Yellow Carp devices do not need rrc */ >> pdata->vdata->enable_rrc = 0; >> break; >> + case 0x1630: > > What PCI ID is this, it doesn't match the 0x1641 added below? 0x1630 is root hub > > Thanks, > Tom > >> + pdata->xpcs_window_def_reg = PCS_V2_RN_WINDOW_DEF; >> + pdata->xpcs_window_sel_reg = PCS_V2_RN_WINDOW_SELECT; >> + break; >> default: >> pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF; >> pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT; >> break; >> } >> - pci_dev_put(rdev); >> /* Configure the PCS indirect addressing support */ >> - reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); >> + if (pdata->vdata->xpcs_access == XGBE_XPCS_ACCESS_V3) { >> + reg = XP_IOREAD(pdata, XP_PROP_0); >> + pdata->xphy_base = PCS_RN_SMN_BASE_ADDR + >> + (PCS_RN_PORT_ADDR_SIZE * XP_GET_BITS(reg, >> XP_PROP_0, PORT_ID)); >> + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + >> (pdata->xpcs_window_def_reg)); >> + pci_read_config_dword(rdev, 0x64, ®); >> + } else { >> + reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); >> + } >> + pci_dev_put(rdev); >> + >> pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET); >> pdata->xpcs_window <<= 6; >> pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, >> SIZE); >> @@ -481,6 +494,22 @@ static int __maybe_unused xgbe_pci_resume(struct >> device *dev) >> return ret; >> } >> +static struct xgbe_version_data xgbe_v3 = { >> + .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, >> + .xpcs_access = XGBE_XPCS_ACCESS_V3, >> + .mmc_64bit = 1, >> + .tx_max_fifo_size = 65536, >> + .rx_max_fifo_size = 65536, >> + .tx_tstamp_workaround = 1, >> + .ecc_support = 1, >> + .i2c_support = 1, >> + .irq_reissue_support = 1, >> + .tx_desc_prefetch = 5, >> + .rx_desc_prefetch = 5, >> + .an_cdr_workaround = 0, >> + .enable_rrc = 0, >> +}; >> + >> static struct xgbe_version_data xgbe_v2a = { >> .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, >> .xpcs_access = XGBE_XPCS_ACCESS_V2, >> @@ -518,6 +547,8 @@ static const struct pci_device_id xgbe_pci_table[] >> = { >> .driver_data = (kernel_ulong_t)&xgbe_v2a }, >> { PCI_VDEVICE(AMD, 0x1459), >> .driver_data = (kernel_ulong_t)&xgbe_v2b }, >> + { PCI_VDEVICE(AMD, 0x1641), >> + .driver_data = (kernel_ulong_t)&xgbe_v3 }, >> /* Last entry must be zero */ >> { 0, } >> }; >> diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h >> b/drivers/net/ethernet/amd/xgbe/xgbe.h >> index ad136ed493ed..dbb1faaf6185 100644 >> --- a/drivers/net/ethernet/amd/xgbe/xgbe.h >> +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h >> @@ -347,6 +347,10 @@ >> (_src)->link_modes._sname, \ >> __ETHTOOL_LINK_MODE_MASK_NBITS) >> +/* Generic low and high masks */ >> +#define XGBE_GEN_HI_MASK GENMASK(31, 16) >> +#define XGBE_GEN_LO_MASK GENMASK(15, 0) >> + >> struct xgbe_prv_data; >> struct xgbe_packet_data { >> @@ -565,6 +569,7 @@ enum xgbe_speed { >> enum xgbe_xpcs_access { >> XGBE_XPCS_ACCESS_V1 = 0, >> XGBE_XPCS_ACCESS_V2, >> + XGBE_XPCS_ACCESS_V3, >> }; >> enum xgbe_an_mode { >> @@ -1056,6 +1061,7 @@ struct xgbe_prv_data { >> struct device *dev; >> struct platform_device *phy_platdev; >> struct device *phy_dev; >> + unsigned int xphy_base; >> /* Version related data */ >> struct xgbe_version_data *vdata;
On 12/13/23 10:25, Raju Rangoju wrote: > On 12/12/2023 9:02 PM, Tom Lendacky wrote: >> On 12/11/23 23:37, Raju Rangoju wrote: >>> Add the necessary support to enable Crater ethernet device. Since the >>> BAR1 address cannot be used to access the XPCS registers on Crater, use >>> the pci_{read/write}_config_dword calls. Also, include the new pci device >>> id 0x1641 to register Crater device with PCIe. >>> >>> Co-developed-by: Sudheesh Mavila <sudheesh.mavila@amd.com> >>> Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> >>> Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com> >>> --- >>> drivers/net/ethernet/amd/xgbe/xgbe-common.h | 5 ++ >>> drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 93 +++++++++++++++++++++ >>> drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 35 +++++++- >>> drivers/net/ethernet/amd/xgbe/xgbe.h | 6 ++ >>> 4 files changed, 137 insertions(+), 2 deletions(-) >>> >>> + >>> + spin_lock_irqsave(&pdata->xpcs_lock, flags); >>> + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + >>> pdata->xpcs_window_sel_reg)); >>> + pci_write_config_dword(rdev, 0x64, index); >>> + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); >>> + pci_read_config_dword(rdev, 0x64, &ctr_mmd_data); >>> + if (offset % 4) { >>> + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, mmd_data) | >>> + FIELD_GET(XGBE_GEN_LO_MASK, ctr_mmd_data); >>> + } else { >>> + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, >>> + FIELD_GET(XGBE_GEN_HI_MASK, ctr_mmd_data)) | >>> + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); >>> + } >> >> Braces aren't necessary. >> >> Also, just curious, what is the "ctr" prefix meant to imply here? > > ctr = crater. Will use the full name instead to avoid confusion. You should probably make it generic and use pci_ or tmp_ (or smn_ if you end up squashing patches 2 and 3), since this may not be "crater" specific if this is used by another device ID in the future. > >> >> >>> @@ -295,15 +295,28 @@ static int xgbe_pci_probe(struct pci_dev *pdev, >>> const struct pci_device_id *id) >>> /* Yellow Carp devices do not need rrc */ >>> pdata->vdata->enable_rrc = 0; >>> break; >>> + case 0x1630: >> >> What PCI ID is this, it doesn't match the 0x1641 added below? > > 0x1630 is root hub Ah, right, sorry for the noise. Thanks, Tom >
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 3b70f6737633..e1f70f0528ef 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -900,6 +900,11 @@ #define PCS_V2_RV_WINDOW_SELECT 0x1064 #define PCS_V2_YC_WINDOW_DEF 0x18060 #define PCS_V2_YC_WINDOW_SELECT 0x18064 +#define PCS_V2_RN_WINDOW_DEF 0xF8078 +#define PCS_V2_RN_WINDOW_SELECT 0xF807c + +#define PCS_RN_SMN_BASE_ADDR 0x11E00000 +#define PCS_RN_PORT_ADDR_SIZE 0x100000 /* PCS register entry bit positions and sizes */ #define PCS_V2_WINDOW_DEF_OFFSET_INDEX 6 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 6cd003c24a64..a9eb2ffa9f73 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -120,6 +120,7 @@ #include <linux/bitrev.h> #include <linux/crc32.h> #include <linux/crc32poly.h> +#include <linux/pci.h> #include "xgbe.h" #include "xgbe-common.h" @@ -1165,6 +1166,92 @@ static unsigned int get_index_offset(struct xgbe_prv_data *pdata, unsigned int m return pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); } +static int xgbe_read_mmd_regs_v3(struct xgbe_prv_data *pdata, int prtad, + int mmd_reg) +{ + unsigned int mmd_address, index, offset; + struct pci_dev *rdev; + unsigned long flags; + int mmd_data; + + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (!rdev) + return 0; + + mmd_address = get_mmd_address(pdata, mmd_reg); + + /* The PCS registers are accessed using mmio. The underlying + * management interface uses indirect addressing to access the MMD + * register sets. This requires accessing of the PCS register in two + * phases, an address phase and a data phase. + * + * The mmio interface is based on 16-bit offsets and values. All + * register offsets must therefore be adjusted by left shifting the + * offset 1 bit and reading 16 bits of data. + */ + offset = get_index_offset(pdata, mmd_address, &index); + + spin_lock_irqsave(&pdata->xpcs_lock, flags); + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); + pci_write_config_dword(rdev, 0x64, index); + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); + pci_read_config_dword(rdev, 0x64, &mmd_data); + mmd_data = (offset % 4) ? FIELD_GET(XGBE_GEN_HI_MASK, mmd_data) : + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); + pci_dev_put(rdev); + + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); + + return mmd_data; +} + +static void xgbe_write_mmd_regs_v3(struct xgbe_prv_data *pdata, int prtad, + int mmd_reg, int mmd_data) +{ + unsigned int mmd_address, index, offset, ctr_mmd_data; + struct pci_dev *rdev; + unsigned long flags; + + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (!rdev) + return; + + mmd_address = get_mmd_address(pdata, mmd_reg); + + /* The PCS registers are accessed using mmio. The underlying + * management interface uses indirect addressing to access the MMD + * register sets. This requires accessing of the PCS register in two + * phases, an address phase and a data phase. + * + * The mmio interface is based on 16-bit offsets and values. All + * register offsets must therefore be adjusted by left shifting the + * offset 1 bit and writing 16 bits of data. + */ + offset = get_index_offset(pdata, mmd_address, &index); + + spin_lock_irqsave(&pdata->xpcs_lock, flags); + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); + pci_write_config_dword(rdev, 0x64, index); + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + offset); + pci_read_config_dword(rdev, 0x64, &ctr_mmd_data); + if (offset % 4) { + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, mmd_data) | + FIELD_GET(XGBE_GEN_LO_MASK, ctr_mmd_data); + } else { + ctr_mmd_data = FIELD_PREP(XGBE_GEN_HI_MASK, + FIELD_GET(XGBE_GEN_HI_MASK, ctr_mmd_data)) | + FIELD_GET(XGBE_GEN_LO_MASK, mmd_data); + } + + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + pdata->xpcs_window_sel_reg)); + pci_write_config_dword(rdev, 0x64, index); + pci_write_config_dword(rdev, 0x60, (pdata->xphy_base + offset)); + pci_write_config_dword(rdev, 0x64, ctr_mmd_data); + pci_dev_put(rdev); + + spin_unlock_irqrestore(&pdata->xpcs_lock, flags); +} + static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad, int mmd_reg) { @@ -1274,6 +1361,9 @@ static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, case XGBE_XPCS_ACCESS_V1: return xgbe_read_mmd_regs_v1(pdata, prtad, mmd_reg); + case XGBE_XPCS_ACCESS_V3: + return xgbe_read_mmd_regs_v3(pdata, prtad, mmd_reg); + case XGBE_XPCS_ACCESS_V2: default: return xgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg); @@ -1287,6 +1377,9 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, case XGBE_XPCS_ACCESS_V1: return xgbe_write_mmd_regs_v1(pdata, prtad, mmd_reg, mmd_data); + case XGBE_XPCS_ACCESS_V3: + return xgbe_write_mmd_regs_v3(pdata, prtad, mmd_reg, mmd_data); + case XGBE_XPCS_ACCESS_V2: default: return xgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 8b0c1e450b7e..db3e8aac3339 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -295,15 +295,28 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Yellow Carp devices do not need rrc */ pdata->vdata->enable_rrc = 0; break; + case 0x1630: + pdata->xpcs_window_def_reg = PCS_V2_RN_WINDOW_DEF; + pdata->xpcs_window_sel_reg = PCS_V2_RN_WINDOW_SELECT; + break; default: pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF; pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT; break; } - pci_dev_put(rdev); /* Configure the PCS indirect addressing support */ - reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); + if (pdata->vdata->xpcs_access == XGBE_XPCS_ACCESS_V3) { + reg = XP_IOREAD(pdata, XP_PROP_0); + pdata->xphy_base = PCS_RN_SMN_BASE_ADDR + + (PCS_RN_PORT_ADDR_SIZE * XP_GET_BITS(reg, XP_PROP_0, PORT_ID)); + pci_write_config_dword(rdev, 0x60, pdata->xphy_base + (pdata->xpcs_window_def_reg)); + pci_read_config_dword(rdev, 0x64, ®); + } else { + reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); + } + pci_dev_put(rdev); + pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET); pdata->xpcs_window <<= 6; pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE); @@ -481,6 +494,22 @@ static int __maybe_unused xgbe_pci_resume(struct device *dev) return ret; } +static struct xgbe_version_data xgbe_v3 = { + .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, + .xpcs_access = XGBE_XPCS_ACCESS_V3, + .mmc_64bit = 1, + .tx_max_fifo_size = 65536, + .rx_max_fifo_size = 65536, + .tx_tstamp_workaround = 1, + .ecc_support = 1, + .i2c_support = 1, + .irq_reissue_support = 1, + .tx_desc_prefetch = 5, + .rx_desc_prefetch = 5, + .an_cdr_workaround = 0, + .enable_rrc = 0, +}; + static struct xgbe_version_data xgbe_v2a = { .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, .xpcs_access = XGBE_XPCS_ACCESS_V2, @@ -518,6 +547,8 @@ static const struct pci_device_id xgbe_pci_table[] = { .driver_data = (kernel_ulong_t)&xgbe_v2a }, { PCI_VDEVICE(AMD, 0x1459), .driver_data = (kernel_ulong_t)&xgbe_v2b }, + { PCI_VDEVICE(AMD, 0x1641), + .driver_data = (kernel_ulong_t)&xgbe_v3 }, /* Last entry must be zero */ { 0, } }; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index ad136ed493ed..dbb1faaf6185 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -347,6 +347,10 @@ (_src)->link_modes._sname, \ __ETHTOOL_LINK_MODE_MASK_NBITS) +/* Generic low and high masks */ +#define XGBE_GEN_HI_MASK GENMASK(31, 16) +#define XGBE_GEN_LO_MASK GENMASK(15, 0) + struct xgbe_prv_data; struct xgbe_packet_data { @@ -565,6 +569,7 @@ enum xgbe_speed { enum xgbe_xpcs_access { XGBE_XPCS_ACCESS_V1 = 0, XGBE_XPCS_ACCESS_V2, + XGBE_XPCS_ACCESS_V3, }; enum xgbe_an_mode { @@ -1056,6 +1061,7 @@ struct xgbe_prv_data { struct device *dev; struct platform_device *phy_platdev; struct device *phy_dev; + unsigned int xphy_base; /* Version related data */ struct xgbe_version_data *vdata;